Your first error

From an empty account to an error you can see in the dashboard. About ten minutes, and the only thing you need afterwards is the DSN this produces.

1. Create a project and copy the DSN

A project is the unit telemetry is grouped and rate-limited by. Most teams start with one per deployable service rather than one per repository, because that is the unit an on-call engineer thinks in when something breaks.

The DSN appears once the project exists. It is a write credential for that project alone and grants no read access, so it belongs in your deployment configuration rather than in a secret store reserved for credentials that can do damage.

2. Send something from your application

There are SDKs for Go and for JavaScript, including the browser. Both take the DSN from the environment rather than from a literal in your source, which is the difference between rotating a key and shipping a release.

The JavaScript one installs from npm as @snagspy/replay. The Go one does not yet: github.com/snagspy/sdk-go is where it is going and does not exist as a repository yet, so `go get` answers 404 (checked 11 Sep 2026), and this page would rather say so than let you find out from a 404. Until it is published, Go is served by any upstream OpenTelemetry SDK pointed at the ingest host with your DSN — OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.snagspy.com, OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20<your DSN>, and OTEL_SERVICE_NAME. The getting-started page, Part 3.A, has that worked through and executed in Go, Node.js and Python with upstream packages only.

Go
import "github.com/snagspy/sdk-go/snagspy"

func main() {
    ctx := context.Background()

    shutdown, err := snagspy.Init(ctx, snagspy.Options{
        DSN:         os.Getenv("SNAGSPY_DSN"),
        ServiceName: "checkout-api",
        Release:     os.Getenv("COMMIT_SHA"),
    })
    if err != nil {
        log.Fatal(err)
    }
    defer shutdown(ctx)

    snagspy.CaptureError(ctx, errors.New("first error from Go"))
}

3. …or from the browser

The JavaScript SDK installs a handler for uncaught errors and unhandled promise rejections, so the common case needs no call site of its own.

Install it with npm install @snagspy/replay. It takes the whole DSN, splits it and sets the header itself, so nothing here handles the key.

JavaScript
import { init } from '@snagspy/replay/errors'

const snagspy = init({ dsn: globalThis._importMeta_.env.VITE_SNAGSPY_DSN })

snagspy.captureException(new Error('first error from the browser'))

4. Confirm it arrived

The issue appears in the dashboard within a few seconds of being accepted. If nothing arrives, the ingest host answers a liveness check, which separates "my request never landed" from "it landed and was rejected" — two problems with completely different causes.

A rejected write returns a reason rather than a bare failure. The two that account for nearly everything are a DSN that does not match a project, and a payload that is not valid OTLP.

Liveness
curl -i https://ingest.snagspy.com/healthz

What both SDKs do before anything leaves the process

Both redact secret-shaped values locally, before the network. This is not a courtesy performed on arrival: a password sent to us and scrubbed here has still crossed the network and still appeared in whatever sat between us.

It is worth knowing because it changes what you have to be careful about. You still should not deliberately attach credentials to an event, but an accidental token in a stack frame does not become our problem to clean up after the fact.

← Documentation