Go SDK Pro

Send events from any Go server using a project API key. Pure stdlib, no external dependencies. Works with net/http, gin, echo, chi, and any other Go service.

clamp-sh/analytics-goMIT

Paste to your agent

Wire Clamp into a Go service
Adds the clamp Go module, initializes it on startup, and tracks the project's primary conversion event from the relevant handler.

Install

terminal
go get github.com/clamp-sh/analytics-go

Go 1.21+ supported. The package depends only on the standard library.

Use an API key that starts with sk_proj_ from Settings → API Keys. Keys are scoped to one project. Read it from the environment; never commit it.

Quick start

main.go
package main

import (
    "context"
    "log"
    "os"

    clamp "github.com/clamp-sh/analytics-go"
)

func main() {
    clamp.Init("proj_xxx", os.Getenv("CLAMP_API_KEY"))

    err := clamp.Track(context.Background(), "signup", clamp.Properties{
        "plan":   "pro",
        "method": "email",
    })
    if err != nil {
        log.Printf("clamp: %v", err)
    }
}

API

Init(projectID, apiKey string, opts ...InitOption)

Configures the SDK. Call once at process startup. State is held at the package level behind a mutex, so it's safe to use from concurrent goroutines.

Available options:

Track(ctx, name, properties, opts...) error

Sends a server event. Returns nil on success.

Optional via TrackOption:

Returns:

Money

purchase.go
clamp.Track(ctx, "purchase", clamp.Properties{
    "plan":  "pro",
    "total": clamp.Money{Amount: 29.00, Currency: "USD"},
    "tax":   clamp.Money{Amount: 4.35, Currency: "USD"},
})

Amount is in major units. Currency is an ISO 4217 code (uppercase, three letters).

Framework integrations

net/http

signup_handler.go
func signupHandler(w http.ResponseWriter, r *http.Request) {
    user, err := createUser(r)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    anonID, _ := r.Cookie("clamp_aid")
    _ = clamp.Track(r.Context(), "signup", clamp.Properties{
        "plan":   user.Plan,
        "method": "email",
    }, clamp.WithAnonymousID(anonID.Value))

    http.Redirect(w, r, "/welcome", http.StatusSeeOther)
}

gin

checkout.go
func checkoutHandler(c *gin.Context) {
    var payload CheckoutPayload
    if err := c.BindJSON(&payload); err != nil {
        c.AbortWithStatus(http.StatusBadRequest)
        return
    }

    session := createStripeSession(payload)
    _ = clamp.Track(c.Request.Context(), "checkout_started", clamp.Properties{
        "plan": payload.Plan,
    }, clamp.WithAnonymousID(payload.AnonID))

    c.JSON(http.StatusOK, gin.H{"url": session.URL})
}

echo

featureusedhandler.go
func featureUsed(c echo.Context) error {
    user := c.Get("user").(*User)
    _ = clamp.Track(c.Request().Context(), "feature_used", clamp.Properties{
        "feature": c.Param("feature"),
        "plan":    user.Plan,
    })
    return c.NoContent(http.StatusNoContent)
}

Errors and retries

The SDK is synchronous and returns errors on failure. There are no automatic retries. Either ignore the error (fire-and-forget), log it, or hand off to a queue:

background.go
go func() {
    if err := clamp.Track(ctx, "subscription_started", props); err != nil {
        log.Printf("clamp: %v", err)
    }
}()

Linking browser and server events

Pass the anonymous ID from the browser to your API, then use clamp.WithAnonymousID() on server-side calls. See the linking pattern on the server-side docs page; the same pattern applies in Go.