CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/golang-go-mastodon

Go client library for Mastodon API with complete coverage of v1 and v2 endpoints

Overview
Eval results
Files

tags.mddocs/

Hashtag Operations

Complete hashtag information, following, and filtering operations.

Overview

Hashtags allow users to categorize and discover content. Users can follow hashtags to see related posts in their home timeline.

Types

Tag

type Tag struct {
    Name    string
    URL     string
    History []History
}

Tag holds information for a hashtag.

Fields:

  • Name - Hashtag name (without '#' prefix)
  • URL - Web URL for this hashtag
  • History - Usage history entries

FollowedTag

type FollowedTag struct {
    Name      string
    URL       string
    History   []FollowedTagHistory
    Following bool
}

FollowedTag represents a hashtag followed by the user.

Fields:

  • Name - Hashtag name (without '#' prefix)
  • URL - Web URL for this hashtag
  • History - Usage history entries
  • Following - Whether currently following this tag

FollowedTagHistory

type FollowedTagHistory struct {
    Day      UnixTimeString
    Accounts int
    Uses     int
}

FollowedTagHistory represents tag usage history for a single day.

Fields:

  • Day - Date (Unix timestamp string)
  • Accounts - Number of accounts using tag that day (JSON: string)
  • Uses - Number of times tag was used that day (JSON: string)

History

type History struct {
    Day      string
    Uses     string
    Accounts string
}

History holds generic history data.

Fields:

  • Day - Date string
  • Uses - Number of uses (string)
  • Accounts - Number of accounts (string)

TagData

type TagData struct {
    Any  []string
    All  []string
    None []string
}

TagData holds tag filter parameters for timeline queries.

Fields:

  • Any - Statuses containing ANY of these tags
  • All - Statuses containing ALL of these tags
  • None - Statuses containing NONE of these tags

Tag Operations

TagInfo { .api }

func (c *Client) TagInfo(ctx context.Context, tag string) (*FollowedTag, error)

Gets statistics and information about a hashtag.

Parameters:

  • ctx - Context for cancellation/timeout
  • tag - Hashtag name (without '#' prefix)

Returns: FollowedTag with statistics or error

Example:

tagInfo, err := client.TagInfo(ctx, "golang")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("#%s\n", tagInfo.Name)
fmt.Printf("URL: %s\n", tagInfo.URL)
fmt.Printf("Following: %v\n", tagInfo.Following)

fmt.Println("\nRecent Activity:")
for _, hist := range tagInfo.History {
    fmt.Printf("  Day: %s - %d uses by %d accounts\n",
        hist.Day, hist.Uses, hist.Accounts)
}

TagFollow { .api }

func (c *Client) TagFollow(ctx context.Context, tag string) (*FollowedTag, error)

Follows a hashtag (posts with this tag appear in home timeline).

Parameters:

  • ctx - Context for cancellation/timeout
  • tag - Hashtag name (without '#' prefix)

Returns: Updated FollowedTag or error

Example:

followedTag, err := client.TagFollow(ctx, "golang")
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Now following #%s\n", followedTag.Name)

TagUnfollow { .api }

func (c *Client) TagUnfollow(ctx context.Context, ID string) (*FollowedTag, error)

Unfollows a hashtag.

Parameters:

  • ctx - Context for cancellation/timeout
  • ID - Tag ID or name to unfollow

Returns: Updated FollowedTag or error

Example:

unfollowedTag, err := client.TagUnfollow(ctx, "golang")
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Unfollowed #%s\n", unfollowedTag.Name)

TagsFollowed { .api }

func (c *Client) TagsFollowed(ctx context.Context, pg *Pagination) ([]*FollowedTag, error)

Returns a list of hashtags the user follows.

Parameters:

  • ctx - Context for cancellation/timeout
  • pg - Pagination parameters (optional)

Returns: Slice of FollowedTag objects or error

Example:

tags, err := client.TagsFollowed(ctx, nil)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Following %d hashtags:\n", len(tags))
for _, tag := range tags {
    fmt.Printf("  #%s - %s\n", tag.Name, tag.URL)
}

GetFollowedTags { .api }

func (c *Client) GetFollowedTags(ctx context.Context, pg *Pagination) ([]*FollowedTag, error)

Returns the list of hashtags followed by the user (alias for TagsFollowed).

Parameters:

  • ctx - Context for cancellation/timeout
  • pg - Pagination parameters (optional)

Returns: Slice of FollowedTag objects or error

Usage Examples

Example: Follow Multiple Tags

func followTags(client *mastodon.Client, tags []string) error {
    ctx := context.Background()

    for _, tag := range tags {
        followedTag, err := client.TagFollow(ctx, tag)
        if err != nil {
            log.Printf("Failed to follow #%s: %v", tag, err)
            continue
        }
        fmt.Printf("Following #%s\n", followedTag.Name)
    }

    return nil
}

// Usage
tags := []string{"golang", "programming", "opensource"}
err := followTags(client, tags)

Example: Tag Statistics Dashboard

func displayTagStats(client *mastodon.Client, tag string) error {
    ctx := context.Background()

    tagInfo, err := client.TagInfo(ctx, tag)
    if err != nil {
        return err
    }

    fmt.Printf("\n#%s Statistics\n", tagInfo.Name)
    fmt.Println(strings.Repeat("=", 50))
    fmt.Printf("URL: %s\n", tagInfo.URL)
    fmt.Printf("Following: %v\n\n", tagInfo.Following)

    if len(tagInfo.History) > 0 {
        fmt.Println("Recent Activity (7 days):")

        var totalUses, totalAccounts int
        for _, hist := range tagInfo.History {
            totalUses += hist.Uses
            totalAccounts += hist.Accounts
        }

        avgUses := float64(totalUses) / float64(len(tagInfo.History))
        avgAccounts := float64(totalAccounts) / float64(len(tagInfo.History))

        fmt.Printf("  Total uses: %d (avg %.1f/day)\n", totalUses, avgUses)
        fmt.Printf("  Total accounts: %d (avg %.1f/day)\n", totalAccounts, avgAccounts)

        fmt.Println("\nDaily Breakdown:")
        for _, hist := range tagInfo.History {
            fmt.Printf("  %v: %d uses by %d accounts\n",
                hist.Day, hist.Uses, hist.Accounts)
        }
    }

    return nil
}

Example: Manage Followed Tags

type TagManager struct {
    client *mastodon.Client
}

func (tm *TagManager) ListFollowed(ctx context.Context) ([]*mastodon.FollowedTag, error) {
    tags, err := tm.client.TagsFollowed(ctx, nil)
    if err != nil {
        return nil, err
    }

    fmt.Printf("You are following %d hashtags:\n\n", len(tags))
    for i, tag := range tags {
        fmt.Printf("%d. #%s\n", i+1, tag.Name)
    }

    return tags, nil
}

func (tm *TagManager) UnfollowInactive(ctx context.Context, minDailyUses int) error {
    tags, err := tm.client.TagsFollowed(ctx, nil)
    if err != nil {
        return err
    }

    for _, tag := range tags {
        if len(tag.History) == 0 {
            continue
        }

        // Calculate average daily uses
        var totalUses int
        for _, hist := range tag.History {
            totalUses += hist.Uses
        }
        avgUses := totalUses / len(tag.History)

        if avgUses < minDailyUses {
            _, err := tm.client.TagUnfollow(ctx, tag.Name)
            if err != nil {
                log.Printf("Failed to unfollow #%s: %v", tag.Name, err)
                continue
            }
            fmt.Printf("Unfollowed #%s (avg %.1f uses/day)\n", tag.Name, float64(avgUses))
        }
    }

    return nil
}

func (tm *TagManager) FollowRelated(ctx context.Context, baseTag string, limit int) error {
    // Get timeline for base tag
    statuses, err := tm.client.GetTimelineHashtag(ctx, baseTag, false, nil)
    if err != nil {
        return err
    }

    // Count related tags
    tagCount := make(map[string]int)
    for _, status := range statuses {
        for _, tag := range status.Tags {
            if tag.Name != baseTag {
                tagCount[tag.Name]++
            }
        }
    }

    // Sort by frequency
    type tagFreq struct {
        name  string
        count int
    }
    var tags []tagFreq
    for name, count := range tagCount {
        tags = append(tags, tagFreq{name, count})
    }
    sort.Slice(tags, func(i, j int) bool {
        return tags[i].count > tags[j].count
    })

    // Follow top tags
    fmt.Printf("Related tags to #%s:\n", baseTag)
    for i := 0; i < limit && i < len(tags); i++ {
        fmt.Printf("  #%s (mentioned %d times)\n", tags[i].name, tags[i].count)

        _, err := tm.client.TagFollow(ctx, tags[i].name)
        if err != nil {
            log.Printf("Failed to follow #%s: %v", tags[i].name, err)
        }
    }

    return nil
}

Example: Tag Trending Analysis

func analyzeTrending(client *mastodon.Client, tags []string) error {
    ctx := context.Background()

    type tagMetrics struct {
        name          string
        totalUses     int
        totalAccounts int
        trend         string // "rising", "stable", "falling"
    }

    var metrics []tagMetrics

    for _, tagName := range tags {
        tagInfo, err := client.TagInfo(ctx, tagName)
        if err != nil {
            log.Printf("Error getting info for #%s: %v", tagName, err)
            continue
        }

        if len(tagInfo.History) < 2 {
            continue
        }

        var total int
        for _, hist := range tagInfo.History {
            total += hist.Uses
        }

        // Compare recent vs older activity
        recentUses := tagInfo.History[0].Uses + tagInfo.History[1].Uses
        olderUses := tagInfo.History[len(tagInfo.History)-2].Uses +
            tagInfo.History[len(tagInfo.History)-1].Uses

        trend := "stable"
        if recentUses > olderUses*1.5 {
            trend = "rising"
        } else if recentUses < olderUses*0.5 {
            trend = "falling"
        }

        metrics = append(metrics, tagMetrics{
            name:      tagName,
            totalUses: total,
            trend:     trend,
        })
    }

    // Display results
    fmt.Println("Tag Trend Analysis")
    fmt.Println(strings.Repeat("=", 50))

    for _, m := range metrics {
        indicator := "→"
        if m.trend == "rising" {
            indicator = "↑"
        } else if m.trend == "falling" {
            indicator = "↓"
        }

        fmt.Printf("%s #%-20s %d uses (%s)\n",
            indicator, m.name, m.totalUses, m.trend)
    }

    return nil
}

Example: Tag Recommendation System

func recommendTags(client *mastodon.Client, basedOnAccount mastodon.ID) ([]string, error) {
    ctx := context.Background()

    // Get account's recent statuses
    statuses, err := client.GetAccountStatuses(ctx, basedOnAccount, &mastodon.Pagination{Limit: 40})
    if err != nil {
        return nil, err
    }

    // Count tag usage
    tagFreq := make(map[string]int)
    for _, status := range statuses {
        for _, tag := range status.Tags {
            tagFreq[tag.Name]++
        }
    }

    // Get currently followed tags
    following, err := client.TagsFollowed(ctx, nil)
    if err != nil {
        return nil, err
    }

    followedMap := make(map[string]bool)
    for _, tag := range following {
        followedMap[tag.Name] = true
    }

    // Recommend frequent but not followed tags
    var recommendations []string
    for tag, freq := range tagFreq {
        if !followedMap[tag] && freq >= 3 {
            recommendations = append(recommendations, tag)
        }
    }

    // Sort by frequency
    sort.Slice(recommendations, func(i, j int) bool {
        return tagFreq[recommendations[i]] > tagFreq[recommendations[j]]
    })

    return recommendations, nil
}

Example: Tag-Based Content Filtering

func filterByTags(statuses []*mastodon.Status, requiredTags, excludeTags []string) []*mastodon.Status {
    var filtered []*mastodon.Status

    for _, status := range statuses {
        statusTags := make(map[string]bool)
        for _, tag := range status.Tags {
            statusTags[strings.ToLower(tag.Name)] = true
        }

        // Check exclusions first
        excluded := false
        for _, excludeTag := range excludeTags {
            if statusTags[strings.ToLower(excludeTag)] {
                excluded = true
                break
            }
        }
        if excluded {
            continue
        }

        // Check required tags
        if len(requiredTags) == 0 {
            filtered = append(filtered, status)
            continue
        }

        hasRequired := false
        for _, requiredTag := range requiredTags {
            if statusTags[strings.ToLower(requiredTag)] {
                hasRequired = true
                break
            }
        }

        if hasRequired {
            filtered = append(filtered, status)
        }
    }

    return filtered
}

Advanced Tag Filtering

Using TagData with Timeline Queries

// Posts with #golang AND (#programming OR #coding) but NOT #beginner
tagData := &mastodon.TagData{
    All:  []string{"programming"},      // Must have this
    Any:  []string{"coding", "tutorial"}, // Plus one of these
    None: []string{"beginner"},          // But not this
}

statuses, err := client.GetTimelineHashtagMultiple(
    ctx,
    "golang",  // Primary tag
    false,     // Include federated
    tagData,   // Additional filters
    nil,       // Pagination
)

Best Practices

1. Follow Relevant Tags

Follow tags that match your interests:

interests := []string{"golang", "opensource", "webdev"}
for _, tag := range interests {
    client.TagFollow(ctx, tag)
}

2. Monitor Tag Activity

Check tag statistics before following:

tagInfo, _ := client.TagInfo(ctx, "sometag")
if len(tagInfo.History) > 0 {
    avgUses := calculateAverage(tagInfo.History)
    if avgUses >= 10 { // Minimum activity threshold
        client.TagFollow(ctx, "sometag")
    }
}

3. Periodically Review Followed Tags

Clean up inactive or no-longer-relevant tags:

tags, _ := client.TagsFollowed(ctx, nil)
for _, tag := range tags {
    // Review and unfollow if needed
    if shouldUnfollow(tag) {
        client.TagUnfollow(ctx, tag.Name)
    }
}

4. Use Tag Names Without Hash Symbol

API expects tag names without '#':

// Correct
client.TagFollow(ctx, "golang")

// Incorrect
client.TagFollow(ctx, "#golang")

5. Combine Multiple Tags

Use TagData for complex filtering:

tagData := &mastodon.TagData{
    All:  []string{"tech"},
    Any:  []string{"news", "tutorial"},
    None: []string{"clickbait"},
}

Related Types

See also:

  • Timelines - For hashtag timelines
  • Streaming - For streaming hashtag events
  • Accounts - For followed tags on accounts
  • Types - For common types

Install with Tessl CLI

npx tessl i tessl/golang-go-mastodon

docs

accounts.md

authentication.md

conversations.md

filters.md

index.md

instance.md

lists.md

media.md

notifications.md

polls.md

reports.md

search.md

statuses.md

streaming.md

tags.md

timelines.md

types.md

tile.json