Home/Go SDK
SDK

Go SDK

Go 1.23+pkg.go.devGitHub

Go client for the ScrapingIsNotACrime API: package sinac, context on every call, typed structs, standard library only.

pkg.go.devRepository

01Install

bash
go get github.com/ScrapingIsNotACrime/sdk-go

The module has no third-party dependencies.

02Quick start

go
package main

import (
	"context"
	"errors"
	"fmt"
	"log"

	sinac "github.com/ScrapingIsNotACrime/sdk-go"
)

func main() {
	client, err := sinac.NewClient(sinac.WithAPIKey("sinac_..."))
	if err != nil {
		log.Fatal(err)
	}

	profile, err := client.Instagram.Profile(context.Background(), "nasa")
	if errors.Is(err, sinac.ErrNotFound) {
		fmt.Println("no such profile")
		return
	}
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(profile.Username, profile.Followers)
}

Get a key at your dashboard. Keys start with sinac_, and new accounts get 100 free credits.

NewClient also reads SCRAPINGISNOTACRIME_API_KEY, so sinac.NewClient() with no options works when it is set.

03Configuration

go
client, err := sinac.NewClient(
	sinac.WithAPIKey("sinac_..."),
	sinac.WithBaseURL("https://api.scrapingisnotacrime.com/v1"),
	sinac.WithTimeout(30*time.Second),
	sinac.WithMaxRetries(2),
	sinac.WithHTTPClient(nil),
)
OptionDefaultDescription
WithAPIKeySCRAPINGISNOTACRIME_API_KEYYour API key. NewClient returns an error if none is set. Defaults to the SCRAPINGISNOTACRIME_API_KEY environment variable.
WithBaseURLhttps://api.scrapingisnotacrime.com/v1API base URL. Redirects are not followed, so use the final HTTPS URL.
WithTimeout30 * time.SecondPer attempt, covering connect, headers and the whole body read.
WithMaxRetries2Extra attempts for 429, 502 and network errors. 0 disables retries.
WithHTTPClient*http.ClientBring your own *http.Client. It is never modified. Defaults to a new *http.Client.

04Methods

05Pagination

Page has Items, HasMore, NextCursor or NextPage, and Data. Range over page.All(ctx) to iterate every item, or call page.Next(ctx) page by page.

Each page fetched is one billed request, so bound your loops. Breaking out early stops fetching.

go
page, err := client.GitHub.Followers(ctx, "torvalds", &sinac.GitHubListParams{Limit: 100})
if err != nil {
	log.Fatal(err)
}

n := 0
for user, err := range page.All(ctx) {
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(user.Username)
	if n++; n >= 250 {
		break // stop early; no further pages are fetched
	}
}
next
page, err := client.Bluesky.Posts(ctx, "bsky.app", &sinac.BlueskyPostsParams{Limit: 25})
// Each page fetched is one billed request, so stop after a bounded number of pages.
for fetched := 0; page != nil && err == nil && fetched < 3; fetched++ {
	for _, post := range page.Items {
		fmt.Println(post.Text)
	}
	page, err = page.Next(ctx)
}
if err != nil {
	log.Fatal(err)
}

06Errors

Every API, network and argument failure is a *sinac.Error with Status, Message and RequestID. Match it with errors.Is against the sentinels, or read its fields with errors.As.

TypeStatusRetried
ErrBadRequest400, or an invalid path argumentno
ErrAuthentication401no
ErrQuotaExceeded402no
ErrNotFound404no
ErrRateLimit429yes
ErrUpstream502yes
ErrConnectionnetwork failure or per-attempt timeoutyes
ErrAPIany other status, a 2xx without the JSON envelope, or a redirect (not followed)no
go
var apiErr *sinac.Error
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.Status, apiErr.RequestID)
}
switch
profile, err := client.TikTok.Profile(ctx, "this-user-does-not-exist-123")
switch {
case errors.Is(err, sinac.ErrNotFound):
	fmt.Println("no such profile")
case errors.Is(err, sinac.ErrQuotaExceeded):
	log.Fatal(err) // includes the pricing link in Message
case errors.Is(err, sinac.ErrRateLimit):
	fmt.Println("TikTok is rate limiting; already retried, try again later")
case err != nil:
	log.Fatal(err)
default:
	fmt.Println(profile.Username)
}

07Retries

Rate limits (429), upstream failures (502) and network failures or timeouts are retried automatically, up to 2 extra attempts by default. These failures don't consume credits. The wait honors the Retry-After header; otherwise it is exponential backoff with jitter, starting at 500 ms and capped at 10 seconds.

Use WithMaxRetries(0) to disable retries.

08Context and cancellation

A cancelled or expired ctx, including while the client waits between retries, makes the call return at once with an error matching errors.Is(err, ctx.Err()). Cancellation is never retried.

A per-attempt timeout is reported as ErrConnection. Check ctx.Err() to tell it apart from your own deadline.

With your consent, we use Google Analytics and non-personalized Google Ads measurement to understand how the site and the dashboard are used and whether our ads work β€” pages visited and actions like creating an API key or testing a request. We never send Google your email, name, account ID, API keys or request content. You can change your mind anytime in Cookie preferences, in the footer.