Skip to content

tirthpatell/threads-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

112 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Threads API Go Client

Go Reference Go Report Card CI codecov License: MIT Coverage

Unofficial, production-ready Go client for the Threads API with complete endpoint coverage, OAuth 2.0 authentication, rate limiting, and comprehensive error handling. Not affiliated with or endorsed by Meta.

Requires Go 1.21+. Tested on Go 1.21-1.24.

Features

  • Complete API coverage (posts, users, replies, insights, locations, search)
  • GIF attachments (GIPHY), ghost posts, and reply approvals
  • Fluent ContainerBuilder for advanced post creation
  • OAuth 2.0 flow and existing token support
  • Intelligent rate limiting with exponential backoff
  • Type-safe error handling with transient error detection
  • Thread-safe concurrent usage
  • Comprehensive test coverage

Installation

go get github.com/tirthpatell/threads-go

Quick Start

With Existing Token

client, err := threads.NewClientWithToken("your-access-token", &threads.Config{
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret",
    RedirectURI:  "your-redirect-uri",
})

// Create a post
post, err := client.CreateTextPost(context.Background(), &threads.TextPostContent{
    Text: "Hello Threads!",
})

OAuth Flow

config := &threads.Config{
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret", 
    RedirectURI:  "your-redirect-uri",
    Scopes:       []string{"threads_basic", "threads_content_publish"},
}

client, err := threads.NewClient(config)

// Get authorization URL
authURL := client.GetAuthURL(config.Scopes)
// Redirect user to authURL

// Exchange authorization code for token
ctx := context.Background()
err = client.ExchangeCodeForToken(ctx, "auth-code-from-callback")
err = client.GetLongLivedToken(ctx) // Convert to long-lived token

App Access Tokens

For APIs that require app-level auth instead of user tokens (e.g., oEmbed):

// Full API call (server-side only — exposes app secret)
tokenResp, err := client.GetAppAccessToken(ctx)

// Or use the shorthand format (no API call needed)
shorthand := client.GetAppAccessTokenShorthand() // "TH|<APP_ID>|<APP_SECRET>"

Environment Variables

export THREADS_CLIENT_ID="your-client-id"
export THREADS_CLIENT_SECRET="your-client-secret"
export THREADS_REDIRECT_URI="your-redirect-uri"
export THREADS_ACCESS_TOKEN="your-access-token"  # optional
client, err := threads.NewClientFromEnv()

Available Scopes

  • threads_basic - Basic profile access
  • threads_content_publish - Create and publish posts
  • threads_manage_insights - Access analytics data
  • threads_manage_replies - Manage replies and conversations
  • threads_read_replies - Read replies to posts
  • threads_keyword_search - Search functionality
  • threads_delete - Delete posts
  • threads_location_tagging - Location services

API Usage

Posts

// Create different post types
textPost, err := client.CreateTextPost(ctx, &threads.TextPostContent{
    Text: "Hello Threads!",
})

imagePost, err := client.CreateImagePost(ctx, &threads.ImagePostContent{
    Text: "Check this out!",
    ImageURL: "https://example.com/image.jpg",
})

// Get posts
post, err := client.GetPost(ctx, threads.PostID("123"))
posts, err := client.GetUserPosts(ctx, threads.UserID("456"), &threads.PaginationOptions{Limit: 25})

// Delete post
deletedID, err := client.DeletePost(ctx, threads.PostID("123"))

Users & Profiles

// Get user info
me, err := client.GetMe(ctx)
user, err := client.GetUser(ctx, threads.UserID("123"))

// Public profiles
publicUser, err := client.LookupPublicProfile(ctx, "@username")
posts, err := client.GetPublicProfilePosts(ctx, "username", nil)

Replies & Conversations

// Reply to posts
reply, err := client.ReplyToPost(ctx, threads.PostID("123"), &threads.PostContent{
    Text: "Great post!",
})

// Get replies
replies, err := client.GetReplies(ctx, threads.PostID("123"), &threads.RepliesOptions{Limit: 50})

// Manage visibility
err = client.HideReply(ctx, threads.PostID("456"))

Insights & Analytics

// Post insights
insights, err := client.GetPostInsights(ctx, threads.PostID("123"), []string{"views", "likes"})

// Account insights  
insights, err := client.GetAccountInsights(ctx, threads.UserID("456"), []string{"views"}, "lifetime")

Search & Locations

// Search posts by keyword
results, err := client.KeywordSearch(ctx, "golang", &threads.SearchOptions{Limit: 25})

// Search posts filtered by media type
imageResults, err := client.KeywordSearch(ctx, "nature", &threads.SearchOptions{
    MediaType: threads.MediaTypeImage,  // Filter for IMAGE posts only (TEXT, IMAGE, or VIDEO)
    Limit: 25,
})

// Search posts by topic tag
tagResults, err := client.KeywordSearch(ctx, "#technology", &threads.SearchOptions{
    SearchMode: threads.SearchModeTag,
    Limit: 25,
})

// Location search
locations, err := client.SearchLocations(ctx, "New York", nil, nil)

GIF Posts

// Create a post with a GIF attachment (GIPHY)
gifPost, err := client.CreateTextPost(ctx, &threads.TextPostContent{
    Text: "Check out this GIF!",
    GIFAttachment: &threads.GIFAttachment{
        GIFID:    "giphy-gif-id",
        Provider: threads.GIFProviderGiphy,
    },
})

Note: Tenor support is deprecated and will be sunset on March 31, 2026. Use GIPHY instead.

Ghost Posts

// Create a ghost post (auto-expiring)
ghost, err := client.CreateTextPost(ctx, &threads.TextPostContent{
    Text:        "This will disappear!",
    IsGhostPost: true,
})

// Retrieve a user's ghost posts
ghosts, err := client.GetUserGhostPosts(ctx, userID, nil)

Reply Approvals

// Approve or ignore pending replies
err = client.ApprovePendingReply(ctx, threads.PostID("reply-id"))
err = client.IgnorePendingReply(ctx, threads.PostID("reply-id"))

Container Builder

For advanced post creation, use the fluent ContainerBuilder:

builder := threads.NewContainerBuilder().
    SetMediaType("TEXT").
    SetText("Hello from the builder!").
    SetReplyControl(threads.ReplyControlFollowersOnly).
    SetTopicTag("golang").
    SetLocationID("location-id")
params := builder.Build()

Pagination & Iterators

For large datasets, use iterators to automatically handle pagination:

// Posts iterator
userID := threads.ConvertToUserID("user_id")
iterator := threads.NewPostIterator(client, userID, &threads.PostsOptions{
    Limit: 25,
})

for iterator.HasNext() {
    response, err := iterator.Next(ctx)
    if err != nil {
        log.Fatal(err)
    }
    
    for _, post := range response.Data {
        fmt.Printf("Post: %s\n", post.Text)
    }
}

// Replies iterator
replyIterator := threads.NewReplyIterator(client, threads.PostID("123"), &threads.RepliesOptions{
    Limit: 50,
})

// Search iterator
searchIterator := threads.NewSearchIterator(client, "golang", "keyword", &threads.SearchOptions{
    Limit: 25,
})

// Collect all results at once
allPosts, err := iterator.Collect(ctx)

Configuration

config := &threads.Config{
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret",
    RedirectURI:  "https://yourapp.com/callback",
    Scopes:       []string{"threads_basic", "threads_content_publish"},
    HTTPTimeout:  30 * time.Second,
    Debug:        false,
}

For advanced configuration including retry logic, custom logging, and token storage, see the GoDoc documentation.

Error Handling

The client provides typed errors for different scenarios:

switch {
case threads.IsAuthenticationError(err):
    // Handle authentication issues
case threads.IsRateLimitError(err):
    rateLimitErr := err.(*threads.RateLimitError)
    time.Sleep(rateLimitErr.RetryAfter)
case threads.IsValidationError(err):
    validationErr := err.(*threads.ValidationError)
    log.Printf("Invalid %s: %s", validationErr.Field, err.Error())
case threads.IsTransientError(err):
    // Safe to retry — transient API error
}

Error types: AuthenticationError, RateLimitError, ValidationError, NetworkError, APIError

Testing

# Unit tests
go test ./...

# Integration tests (requires valid credentials)
export THREADS_ACCESS_TOKEN="your-token"
go test ./tests/integration/...

Contributing

See CONTRIBUTING.md for guidelines.

Official Documentation

License

MIT License - see LICENSE file for details.

Contributors

Languages