Complete instance metadata, configuration, and statistics operations.
Instance endpoints provide information about Mastodon servers including configuration, statistics, activity, and federated peers.
type Instance struct {
URI string
Title string
Description string
EMail string
Version string
Thumbnail string
URLs map[string]string
Stats *InstanceStats
Languages []string
ContactAccount *Account
Configuration *InstanceConfig
}Instance holds information for a Mastodon instance.
Fields:
URI - Instance domain (e.g., "mastodon.social")Title - Instance nameDescription - Instance description (HTML)EMail - Admin contact emailVersion - Mastodon version stringThumbnail - Instance thumbnail image URLURLs - Streaming API URLs and other endpointsStats - Instance statisticsLanguages - Supported language codesContactAccount - Contact account for adminConfiguration - Instance configuration limitsMethod:
func (c *Instance) GetConfig() *InstanceConfigReturns instance configuration.
type InstanceConfig struct {
Accounts *InstanceConfigMap
Statuses *InstanceConfigMap
MediaAttachments map[string]interface{}
Polls *InstanceConfigMap
}InstanceConfig holds configuration limits accessible to clients.
Fields:
Accounts - Account-related limitsStatuses - Status-related limitsMediaAttachments - Media file size and type limitsPolls - Poll-related limitstype InstanceConfigMap map[string]interface{}InstanceConfigMap is a type alias for configuration maps.
Configuration examples:
Accounts: max_featured_tags, max_pinned_statusesStatuses: max_characters, max_media_attachmentsMediaAttachments: supported_mime_types, image_size_limit, video_size_limitPolls: max_options, max_characters_per_option, min_expiration, max_expirationtype InstanceStats struct {
UserCount int64
StatusCount int64
DomainCount int64
}InstanceStats holds statistics for a Mastodon instance.
Fields:
UserCount - Total registered usersStatusCount - Total statuses postedDomainCount - Number of known instances (federated peers)type WeeklyActivity struct {
Week Unixtime
Statuses int64
Logins int64
Registrations int64
}WeeklyActivity holds weekly activity statistics.
Fields:
Week - Week timestampStatuses - Number of statuses posted that weekLogins - Number of logins that weekRegistrations - Number of new registrations that weekfunc (c *Client) GetInstance(ctx context.Context) (*Instance, error)Returns information about the instance.
Parameters:
ctx - Context for cancellation/timeoutReturns: Instance information or error
Example:
instance, err := client.GetInstance(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Instance: %s\n", instance.Title)
fmt.Printf("URI: %s\n", instance.URI)
fmt.Printf("Version: %s\n", instance.Version)
fmt.Printf("Description: %s\n", instance.Description)
if instance.Stats != nil {
fmt.Printf("\nStatistics:\n")
fmt.Printf(" Users: %d\n", instance.Stats.UserCount)
fmt.Printf(" Statuses: %d\n", instance.Stats.StatusCount)
fmt.Printf(" Federated instances: %d\n", instance.Stats.DomainCount)
}
if instance.ContactAccount != nil {
fmt.Printf("\nAdmin: @%s\n", instance.ContactAccount.Acct)
}func (c *Client) GetInstanceActivity(ctx context.Context) ([]*WeeklyActivity, error)Returns instance activity statistics by week.
Parameters:
ctx - Context for cancellation/timeoutReturns: Slice of WeeklyActivity objects or error
Example:
activities, err := client.GetInstanceActivity(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println("Weekly Activity:")
for _, activity := range activities {
fmt.Printf("Week of %s:\n", time.Time(activity.Week).Format("2006-01-02"))
fmt.Printf(" Statuses: %d\n", activity.Statuses)
fmt.Printf(" Logins: %d\n", activity.Logins)
fmt.Printf(" New users: %d\n", activity.Registrations)
}func (c *Client) GetInstancePeers(ctx context.Context) ([]string, error)Returns instance peers (other federated instances this instance knows about).
Parameters:
ctx - Context for cancellation/timeoutReturns: Slice of peer domain strings or error
Example:
peers, err := client.GetInstancePeers(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Known instances: %d\n", len(peers))
for i, peer := range peers {
if i < 10 { // Show first 10
fmt.Printf(" %s\n", peer)
}
}
if len(peers) > 10 {
fmt.Printf(" ... and %d more\n", len(peers)-10)
}func displayInstanceInfo(client *mastodon.Client) error {
ctx := context.Background()
instance, err := client.GetInstance(ctx)
if err != nil {
return err
}
fmt.Println("╔" + strings.Repeat("═", 60) + "╗")
fmt.Printf("║ %-58s ║\n", instance.Title)
fmt.Println("╠" + strings.Repeat("═", 60) + "╣")
fmt.Printf("║ URI: %-47s ║\n", instance.URI)
fmt.Printf("║ Version: %-47s ║\n", instance.Version)
if instance.Stats != nil {
fmt.Println("╠" + strings.Repeat("═", 60) + "╣")
fmt.Printf("║ Users: %-47d ║\n", instance.Stats.UserCount)
fmt.Printf("║ Posts: %-47d ║\n", instance.Stats.StatusCount)
fmt.Printf("║ Federation: %-47d ║\n", instance.Stats.DomainCount)
}
if len(instance.Languages) > 0 {
fmt.Println("╠" + strings.Repeat("═", 60) + "╣")
langs := strings.Join(instance.Languages, ", ")
fmt.Printf("║ Languages: %-47s ║\n", langs)
}
fmt.Println("╚" + strings.Repeat("═", 60) + "╝")
return nil
}func checkInstanceLimits(client *mastodon.Client) error {
ctx := context.Background()
instance, err := client.GetInstance(ctx)
if err != nil {
return err
}
if instance.Configuration == nil {
fmt.Println("Configuration not available")
return nil
}
fmt.Println("Instance Limits:")
// Status limits
if instance.Configuration.Statuses != nil {
if maxChars, ok := (*instance.Configuration.Statuses)["max_characters"]; ok {
fmt.Printf(" Max status length: %v characters\n", maxChars)
}
if maxMedia, ok := (*instance.Configuration.Statuses)["max_media_attachments"]; ok {
fmt.Printf(" Max media per post: %v\n", maxMedia)
}
}
// Media limits
if instance.Configuration.MediaAttachments != nil {
if imgLimit, ok := instance.Configuration.MediaAttachments["image_size_limit"]; ok {
fmt.Printf(" Max image size: %v bytes\n", imgLimit)
}
if vidLimit, ok := instance.Configuration.MediaAttachments["video_size_limit"]; ok {
fmt.Printf(" Max video size: %v bytes\n", vidLimit)
}
}
// Poll limits
if instance.Configuration.Polls != nil {
if maxOpts, ok := (*instance.Configuration.Polls)["max_options"]; ok {
fmt.Printf(" Max poll options: %v\n", maxOpts)
}
if maxExp, ok := (*instance.Configuration.Polls)["max_expiration"]; ok {
fmt.Printf(" Max poll duration: %v seconds\n", maxExp)
}
}
return nil
}func analyzeInstanceActivity(client *mastodon.Client) error {
ctx := context.Background()
activities, err := client.GetInstanceActivity(ctx)
if err != nil {
return err
}
if len(activities) == 0 {
fmt.Println("No activity data available")
return nil
}
fmt.Println("Instance Activity Analysis")
fmt.Println(strings.Repeat("=", 50))
// Calculate totals and averages
var totalStatuses, totalLogins, totalRegistrations int64
for _, activity := range activities {
totalStatuses += activity.Statuses
totalLogins += activity.Logins
totalRegistrations += activity.Registrations
}
weeks := len(activities)
fmt.Printf("\nLast %d weeks:\n", weeks)
fmt.Printf(" Total statuses: %d (avg %.1f/week)\n",
totalStatuses, float64(totalStatuses)/float64(weeks))
fmt.Printf(" Total logins: %d (avg %.1f/week)\n",
totalLogins, float64(totalLogins)/float64(weeks))
fmt.Printf(" Total registrations: %d (avg %.1f/week)\n",
totalRegistrations, float64(totalRegistrations)/float64(weeks))
// Find most active week
maxStatuses := int64(0)
var mostActiveWeek time.Time
for _, activity := range activities {
if activity.Statuses > maxStatuses {
maxStatuses = activity.Statuses
mostActiveWeek = time.Time(activity.Week)
}
}
fmt.Printf("\nMost active week: %s (%d statuses)\n",
mostActiveWeek.Format("2006-01-02"), maxStatuses)
// Calculate growth trend
if len(activities) >= 4 {
recentWeeks := activities[:2]
olderWeeks := activities[len(activities)-2:]
recentAvg := (recentWeeks[0].Statuses + recentWeeks[1].Statuses) / 2
olderAvg := (olderWeeks[0].Statuses + olderWeeks[1].Statuses) / 2
if recentAvg > olderAvg {
growth := float64(recentAvg-olderAvg) / float64(olderAvg) * 100
fmt.Printf("\nGrowth trend: +%.1f%% (increasing activity)\n", growth)
} else if recentAvg < olderAvg {
decline := float64(olderAvg-recentAvg) / float64(olderAvg) * 100
fmt.Printf("\nGrowth trend: -%.1f%% (declining activity)\n", decline)
} else {
fmt.Println("\nGrowth trend: Stable")
}
}
return nil
}func analyzeFederation(client *mastodon.Client) error {
ctx := context.Background()
peers, err := client.GetInstancePeers(ctx)
if err != nil {
return err
}
fmt.Printf("Federation Analysis\n")
fmt.Println(strings.Repeat("=", 50))
fmt.Printf("Total federated instances: %d\n\n", len(peers))
// Analyze by TLD
tldCount := make(map[string]int)
for _, peer := range peers {
parts := strings.Split(peer, ".")
if len(parts) >= 2 {
tld := parts[len(parts)-1]
tldCount[tld]++
}
}
// Sort by count
type tldInfo struct {
tld string
count int
}
var tlds []tldInfo
for tld, count := range tldCount {
tlds = append(tlds, tldInfo{tld, count})
}
sort.Slice(tlds, func(i, j int) bool {
return tlds[i].count > tlds[j].count
})
fmt.Println("Top TLDs:")
for i := 0; i < 10 && i < len(tlds); i++ {
percentage := float64(tlds[i].count) / float64(len(peers)) * 100
fmt.Printf(" .%-10s %4d instances (%.1f%%)\n",
tlds[i].tld, tlds[i].count, percentage)
}
return nil
}type InstanceInfo struct {
URI string
Users int64
Statuses int64
Version string
}
func compareInstances(client1, client2 *mastodon.Client) error {
ctx := context.Background()
inst1, err := client1.GetInstance(ctx)
if err != nil {
return err
}
inst2, err := client2.GetInstance(ctx)
if err != nil {
return err
}
fmt.Println("Instance Comparison")
fmt.Println(strings.Repeat("=", 70))
fmt.Printf("%-25s %-20s %-20s\n", "", inst1.URI, inst2.URI)
fmt.Println(strings.Repeat("-", 70))
if inst1.Stats != nil && inst2.Stats != nil {
fmt.Printf("%-25s %-20d %-20d\n",
"Users", inst1.Stats.UserCount, inst2.Stats.UserCount)
fmt.Printf("%-25s %-20d %-20d\n",
"Statuses", inst1.Stats.StatusCount, inst2.Stats.StatusCount)
fmt.Printf("%-25s %-20d %-20d\n",
"Federation", inst1.Stats.DomainCount, inst2.Stats.DomainCount)
}
fmt.Printf("%-25s %-20s %-20s\n", "Version", inst1.Version, inst2.Version)
return nil
}func checkInstanceHealth(client *mastodon.Client) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
startTime := time.Now()
instance, err := client.GetInstance(ctx)
responseTime := time.Since(startTime)
fmt.Println("Instance Health Check")
fmt.Println(strings.Repeat("=", 50))
if err != nil {
fmt.Printf("❌ Instance unreachable: %v\n", err)
return err
}
fmt.Printf("✓ Instance reachable\n")
fmt.Printf(" Response time: %v\n", responseTime)
fmt.Printf(" Version: %s\n", instance.Version)
if instance.Stats != nil {
fmt.Printf(" Active users: %d\n", instance.Stats.UserCount)
fmt.Printf(" Total posts: %d\n", instance.Stats.StatusCount)
}
// Check activity
activities, err := client.GetInstanceActivity(ctx)
if err == nil && len(activities) > 0 {
recentActivity := activities[0]
if recentActivity.Statuses > 0 {
fmt.Printf("✓ Recent activity detected\n")
fmt.Printf(" Last week: %d posts, %d logins\n",
recentActivity.Statuses, recentActivity.Logins)
} else {
fmt.Printf("⚠ Low recent activity\n")
}
}
// Performance rating
if responseTime < 500*time.Millisecond {
fmt.Println("\n✓ Performance: Excellent")
} else if responseTime < 2*time.Second {
fmt.Println("\n✓ Performance: Good")
} else {
fmt.Println("\n⚠ Performance: Slow")
}
return nil
}func extractConfiguration(client *mastodon.Client) (map[string]interface{}, error) {
ctx := context.Background()
instance, err := client.GetInstance(ctx)
if err != nil {
return nil, err
}
config := make(map[string]interface{})
if instance.Configuration != nil {
if instance.Configuration.Statuses != nil {
config["status_max_chars"] = (*instance.Configuration.Statuses)["max_characters"]
config["status_max_media"] = (*instance.Configuration.Statuses)["max_media_attachments"]
}
if instance.Configuration.MediaAttachments != nil {
config["image_size_limit"] = instance.Configuration.MediaAttachments["image_size_limit"]
config["video_size_limit"] = instance.Configuration.MediaAttachments["video_size_limit"]
}
if instance.Configuration.Polls != nil {
config["poll_max_options"] = (*instance.Configuration.Polls)["max_options"]
config["poll_max_duration"] = (*instance.Configuration.Polls)["max_expiration"]
}
}
return config, nil
}Instance data changes infrequently:
type InstanceCache struct {
instance *mastodon.Instance
fetchedAt time.Time
ttl time.Duration
}
func (ic *InstanceCache) Get(client *mastodon.Client, ctx context.Context) (*mastodon.Instance, error) {
if time.Since(ic.fetchedAt) < ic.ttl && ic.instance != nil {
return ic.instance, nil
}
instance, err := client.GetInstance(ctx)
if err != nil {
return nil, err
}
ic.instance = instance
ic.fetchedAt = time.Now()
return instance, nil
}Verify limits before attempting operations:
config, _ := extractConfiguration(client)
if maxChars, ok := config["status_max_chars"].(float64); ok {
if len(statusText) > int(maxChars) {
return fmt.Errorf("status too long: max %d chars", int(maxChars))
}
}Not all instances provide full configuration:
if instance.Configuration == nil {
// Use sensible defaults
maxChars = 500
} else {
// Extract from config
}Regularly check instance availability:
ticker := time.NewTicker(5 * time.Minute)
for range ticker.C {
checkInstanceHealth(client)
}Instance endpoints count toward rate limits:
// Cache results
cachedInstance, _ := getCachedInstance()
// Don't poll too frequently
time.Sleep(time.Minute)See also: