or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

accounts.mdauthentication.mdconversations.mdfilters.mdindex.mdinstance.mdlists.mdmedia.mdnotifications.mdpolls.mdreports.mdsearch.mdstatuses.mdstreaming.mdtags.mdtimelines.mdtypes.md
tile.json

filters.mddocs/

Content Filters

Complete content filtering operations for hiding unwanted content.

Overview

Filters allow you to automatically hide statuses containing specific phrases or keywords from your timelines and notifications.

Types

Filter

type Filter struct {
    ID           ID
    Phrase       string
    Context      []string
    WholeWord    bool
    ExpiresAt    time.Time
    Irreversible bool
}

Filter is metadata for a content filter.

Fields:

  • ID - Unique filter identifier
  • Phrase - Text to filter (keyword or phrase)
  • Context - Contexts where filter applies (see below)
  • WholeWord - If true, only match whole words
  • ExpiresAt - When filter expires (zero value = never)
  • Irreversible - If true, filtered statuses are dropped completely instead of hidden

Filter Contexts:

  • "home" - Home timeline
  • "notifications" - Notifications
  • "public" - Public timelines
  • "thread" - Conversation threads
  • "account" - Account pages

FilterResult

type FilterResult struct {
    Filter struct {
        ID           string
        Title        string
        Context      []string
        ExpiresAt    time.Time
        FilterAction string
    }
    KeywordMatches []string
    StatusMatches  []string
}

FilterResult represents a filter match on a status.

Fields:

  • Filter - Filter information that matched
  • Filter.ID - Filter ID
  • Filter.Title - Filter title/name
  • Filter.Context - Contexts where filter applies
  • Filter.ExpiresAt - Expiration time
  • Filter.FilterAction - Action taken ("warn" or "hide")
  • KeywordMatches - Keywords that matched
  • StatusMatches - Status IDs that matched

Filter Operations

GetFilters { .api }

func (c *Client) GetFilters(ctx context.Context) ([]*Filter, error)

Returns all filters for the current account.

Parameters:

  • ctx - Context for cancellation/timeout

Returns: Slice of Filter objects or error

Example:

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

fmt.Printf("You have %d active filters:\n", len(filters))
for _, filter := range filters {
    fmt.Printf("  '%s' in %v\n", filter.Phrase, filter.Context)
}

GetFilter { .api }

func (c *Client) GetFilter(ctx context.Context, id ID) (*Filter, error)

Returns a filter by ID.

Parameters:

  • ctx - Context for cancellation/timeout
  • id - Filter ID to retrieve

Returns: Filter object or error

Example:

filter, err := client.GetFilter(ctx, "123456")
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Filter: '%s'\n", filter.Phrase)

CreateFilter { .api }

func (c *Client) CreateFilter(ctx context.Context, filter *Filter) (*Filter, error)

Creates a new filter.

Parameters:

  • ctx - Context for cancellation/timeout
  • filter - Filter configuration

Returns: Created Filter object or error

Example:

// Filter out spoilers from home timeline
filter := &mastodon.Filter{
    Phrase:    "spoiler",
    Context:   []string{"home"},
    WholeWord: true,
}

created, err := client.CreateFilter(ctx, filter)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Created filter: %s (ID: %s)\n", created.Phrase, created.ID)

Example: Temporary Filter

// Filter phrase for 24 hours
expiresAt := time.Now().Add(24 * time.Hour)

filter := &mastodon.Filter{
    Phrase:    "temporary keyword",
    Context:   []string{"home", "notifications"},
    ExpiresAt: expiresAt,
}

created, err := client.CreateFilter(ctx, filter)
if err != nil {
    log.Fatal(err)
}

UpdateFilter { .api }

func (c *Client) UpdateFilter(ctx context.Context, id ID, filter *Filter) (*Filter, error)

Updates an existing filter.

Parameters:

  • ctx - Context for cancellation/timeout
  • id - Filter ID to update
  • filter - Updated filter configuration

Returns: Updated Filter object or error

Example:

// Update filter to apply in more contexts
updated := &mastodon.Filter{
    Phrase:    "spoiler",
    Context:   []string{"home", "public", "notifications"},
    WholeWord: true,
}

result, err := client.UpdateFilter(ctx, "123456", updated)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Filter updated")

DeleteFilter { .api }

func (c *Client) DeleteFilter(ctx context.Context, id ID) error

Deletes a filter.

Parameters:

  • ctx - Context for cancellation/timeout
  • id - Filter ID to delete

Returns: Error if operation fails

Example:

err := client.DeleteFilter(ctx, "123456")
if err != nil {
    log.Fatal(err)
}
fmt.Println("Filter deleted")

Usage Examples

Example: Block Spoilers

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

    for _, topic := range topics {
        filter := &mastodon.Filter{
            Phrase:    topic + " spoiler",
            Context:   []string{"home", "public", "notifications"},
            WholeWord: false,
        }

        _, err := client.CreateFilter(ctx, filter)
        if err != nil {
            return fmt.Errorf("failed to create filter for %s: %w", topic, err)
        }

        fmt.Printf("Created spoiler filter for: %s\n", topic)
    }

    return nil
}

// Usage
topics := []string{"Game of Thrones", "Avengers", "Star Wars"}
err := blockSpoilers(client, topics)

Example: Temporary Event Filter

func filterEvent(client *mastodon.Client, eventName string, duration time.Duration) error {
    ctx := context.Background()

    filter := &mastodon.Filter{
        Phrase:    eventName,
        Context:   []string{"home", "public"},
        WholeWord: true,
        ExpiresAt: time.Now().Add(duration),
    }

    created, err := client.CreateFilter(ctx, filter)
    if err != nil {
        return err
    }

    fmt.Printf("Filtering '%s' for %v (until %s)\n",
        eventName, duration, created.ExpiresAt.Format("2006-01-02 15:04"))

    return nil
}

// Usage: Filter Olympics content for 2 weeks
err := filterEvent(client, "Olympics", 14*24*time.Hour)

Example: Whole Word Filtering

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

    filter := &mastodon.Filter{
        Phrase:    word,
        Context:   []string{"home", "notifications", "public", "thread"},
        WholeWord: true, // Only match complete word
    }

    _, err := client.CreateFilter(ctx, filter)
    if err != nil {
        return err
    }

    // With WholeWord=true:
    //   "cat" matches: "my cat is cute"
    //   "cat" doesn't match: "category", "concatenate"

    fmt.Printf("Created whole-word filter for: %s\n", word)
    return nil
}

Example: Irreversible Filtering

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

    filter := &mastodon.Filter{
        Phrase:       phrase,
        Context:      []string{"home", "notifications"},
        Irreversible: true, // Completely drop from server
    }

    _, err := client.CreateFilter(ctx, filter)
    if err != nil {
        return err
    }

    fmt.Printf("Created irreversible filter for: %s\n", phrase)
    fmt.Println("Warning: Filtered content will be completely dropped, not just hidden")

    return nil
}

Example: Manage Filters

type FilterManager struct {
    client *mastodon.Client
}

func (fm *FilterManager) ListAll(ctx context.Context) error {
    filters, err := fm.client.GetFilters(ctx)
    if err != nil {
        return err
    }

    if len(filters) == 0 {
        fmt.Println("No active filters")
        return nil
    }

    fmt.Printf("Active Filters (%d):\n", len(filters))
    for i, filter := range filters {
        fmt.Printf("\n%d. %s (ID: %s)\n", i+1, filter.Phrase, filter.ID)
        fmt.Printf("   Contexts: %v\n", filter.Context)
        fmt.Printf("   Whole word: %v\n", filter.WholeWord)

        if !filter.ExpiresAt.IsZero() {
            fmt.Printf("   Expires: %s\n", filter.ExpiresAt.Format("2006-01-02 15:04"))
        } else {
            fmt.Printf("   Expires: Never\n")
        }

        if filter.Irreversible {
            fmt.Printf("   Irreversible: Yes (completely dropped)\n")
        }
    }

    return nil
}

func (fm *FilterManager) RemoveExpired(ctx context.Context) error {
    filters, err := fm.client.GetFilters(ctx)
    if err != nil {
        return err
    }

    now := time.Now()
    var removed int

    for _, filter := range filters {
        if !filter.ExpiresAt.IsZero() && filter.ExpiresAt.Before(now) {
            err := fm.client.DeleteFilter(ctx, filter.ID)
            if err != nil {
                log.Printf("Failed to delete expired filter %s: %v", filter.ID, err)
                continue
            }
            removed++
        }
    }

    fmt.Printf("Removed %d expired filters\n", removed)
    return nil
}

func (fm *FilterManager) FindByPhrase(ctx context.Context, phrase string) ([]*mastodon.Filter, error) {
    filters, err := fm.client.GetFilters(ctx)
    if err != nil {
        return nil, err
    }

    var matches []*mastodon.Filter
    for _, filter := range filters {
        if strings.Contains(strings.ToLower(filter.Phrase), strings.ToLower(phrase)) {
            matches = append(matches, filter)
        }
    }

    return matches, nil
}

func (fm *FilterManager) ExtendExpiration(ctx context.Context, filterID mastodon.ID, additionalTime time.Duration) error {
    filter, err := fm.client.GetFilter(ctx, filterID)
    if err != nil {
        return err
    }

    // Calculate new expiration
    var newExpiry time.Time
    if filter.ExpiresAt.IsZero() {
        newExpiry = time.Now().Add(additionalTime)
    } else {
        newExpiry = filter.ExpiresAt.Add(additionalTime)
    }

    // Update filter
    filter.ExpiresAt = newExpiry
    _, err = fm.client.UpdateFilter(ctx, filterID, filter)
    if err != nil {
        return err
    }

    fmt.Printf("Extended filter expiration to: %s\n", newExpiry.Format("2006-01-02 15:04"))
    return nil
}

Example: Bulk Filter Management

func createMultipleFilters(client *mastodon.Client, phrases []string, contexts []string) error {
    ctx := context.Background()

    var created int
    var failed int

    for _, phrase := range phrases {
        filter := &mastodon.Filter{
            Phrase:    phrase,
            Context:   contexts,
            WholeWord: true,
        }

        _, err := client.CreateFilter(ctx, filter)
        if err != nil {
            log.Printf("Failed to create filter for '%s': %v", phrase, err)
            failed++
            continue
        }

        created++
    }

    fmt.Printf("Created %d filters, %d failed\n", created, failed)
    return nil
}

func deleteAllFilters(client *mastodon.Client) error {
    ctx := context.Background()

    filters, err := client.GetFilters(ctx)
    if err != nil {
        return err
    }

    fmt.Printf("Deleting %d filters...\n", len(filters))

    for _, filter := range filters {
        err := client.DeleteFilter(ctx, filter.ID)
        if err != nil {
            log.Printf("Failed to delete filter %s: %v", filter.ID, err)
        }
    }

    fmt.Println("All filters deleted")
    return nil
}

Example: Filter Templates

type FilterTemplate struct {
    Name     string
    Phrases  []string
    Contexts []string
    Duration time.Duration
}

var FilterTemplates = map[string]FilterTemplate{
    "sports": {
        Name:     "Sports Events",
        Phrases:  []string{"Super Bowl", "World Cup", "Olympics"},
        Contexts: []string{"home", "public"},
        Duration: 7 * 24 * time.Hour,
    },
    "politics": {
        Name:     "Politics",
        Phrases:  []string{"election", "congress", "parliament"},
        Contexts: []string{"home", "public", "notifications"},
        Duration: 0, // Permanent
    },
}

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

    template, ok := FilterTemplates[templateName]
    if !ok {
        return fmt.Errorf("template not found: %s", templateName)
    }

    fmt.Printf("Applying filter template: %s\n", template.Name)

    for _, phrase := range template.Phrases {
        filter := &mastodon.Filter{
            Phrase:    phrase,
            Context:   template.Contexts,
            WholeWord: true,
        }

        if template.Duration > 0 {
            filter.ExpiresAt = time.Now().Add(template.Duration)
        }

        _, err := client.CreateFilter(ctx, filter)
        if err != nil {
            log.Printf("Failed to create filter '%s': %v", phrase, err)
            continue
        }

        fmt.Printf("  Created filter: %s\n", phrase)
    }

    return nil
}

Best Practices

1. Use Whole Word Matching

For common words, use WholeWord to avoid false positives:

filter := &mastodon.Filter{
    Phrase:    "cat",
    WholeWord: true, // Avoids matching "category", "concatenate"
}

2. Set Appropriate Contexts

Only filter in contexts where needed:

// For personal annoyances, filter from home
filter.Context = []string{"home"}

// For sensitive topics, filter everywhere
filter.Context = []string{"home", "public", "notifications", "thread"}

3. Use Temporary Filters for Events

Set expiration for time-limited topics:

filter := &mastodon.Filter{
    Phrase:    "conference2024",
    ExpiresAt: time.Now().Add(7 * 24 * time.Hour),
}

4. Be Careful with Irreversible

Irreversible filters permanently drop content:

// Use sparingly - you can't undo this
filter := &mastodon.Filter{
    Irreversible: true, // Content is gone forever
}

5. Test Filters Before Broad Application

Start with specific contexts before applying everywhere:

// Test in home first
filter := &mastodon.Filter{
    Phrase:  "test phrase",
    Context: []string{"home"}, // Just home timeline
}

// After testing, expand
updated := &mastodon.Filter{
    Phrase:  "test phrase",
    Context: []string{"home", "public", "notifications"},
}

6. Regularly Review Filters

Clean up outdated filters:

func reviewFilters(client *mastodon.Client) {
    filters, _ := client.GetFilters(ctx)
    for _, filter := range filters {
        fmt.Printf("Keep filter '%s'? (y/n): ", filter.Phrase)
        // Interactive review...
    }
}

Related Types

See also:

  • Statuses - For filtered status data
  • Timelines - Where filters are applied
  • Types - For ID and other common types