Go
Send vTilt events from Go code by POSTing to the ingest API — compatible with net/http, Gin, Echo, Chi, and any other Go web framework.
There's no native Go SDK yet, but vTilt's wire format is a plain JSON POST so any Go code can emit events. The pattern below uses net/http; the same shape works inside Gin, Echo, Chi, Fiber, gRPC handlers, and standalone tools.
#1. Configure
# .env
VTILT_TOKEN=YOUR_PROJECT_TOKEN
VTILT_HOST=https://www.vtilt.comtext
#2. Capture client
A thread-safe singleton with a buffered channel for fire-and-forget captures. The goroutine drains the channel concurrently so handlers never block on analytics.
// internal/vtilt/vtilt.go
package vtilt
import (
"bytes"
"context"
"encoding/json"
"log/slog"
"net/http"
"os"
"time"
)
type Event struct {
APIKey string `json:"api_key"`
Event string `json:"event"`
DistinctID string `json:"distinct_id"`
Properties map[string]interface{} `json:"properties"`
}
var (
token = os.Getenv("VTILT_TOKEN")
host = getenv("VTILT_HOST", "https://www.vtilt.com")
client = &http.Client{Timeout: 2 * time.Second}
queue = make(chan Event, 1024)
)
func init() {
go drain()
}
func Capture(distinctID, event string, properties map[string]interface{}) {
if properties == nil {
properties = map[string]interface{}{}
}
select {
case queue <- Event{APIKey: token, Event: event, DistinctID: distinctID, Properties: properties}:
default:
// queue full; drop rather than block
}
}
func Identify(distinctID string, properties map[string]interface{}) {
Capture(distinctID, "$identify", map[string]interface{}{"$set": properties})
}
func drain() {
for ev := range queue {
body, _ := json.Marshal(ev)
req, _ := http.NewRequestWithContext(context.Background(), http.MethodPost, host+"/api/e", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
if _, err := client.Do(req); err != nil {
slog.Warn("vtilt capture failed", "err", err)
}
}
}
func getenv(k, def string) string {
if v := os.Getenv(k); v != "" {
return v
}
return def
}go
#3. Capture events
package main
import "myapp/internal/vtilt"
func main() {
vtilt.Identify("user_42", map[string]interface{}{
"email": "alice@example.com",
"plan": "pro",
})
vtilt.Capture("user_42", "purchase_completed", map[string]interface{}{
"amount": 99.99,
"currency": "USD",
})
}go
#4. Gin / Echo / Chi handlers
func checkout(c *gin.Context) {
var req struct{ UserID string `json:"user_id"`; Amount float64 `json:"amount"` }
c.BindJSON(&req)
vtilt.Capture(req.UserID, "purchase_completed", map[string]interface{}{
"amount": req.Amount,
})
c.JSON(200, gin.H{"ok": true})
}go
#Next steps
- Identify & alias — full identification model.
- Event forwarding — fan events out to GA4, Meta CAPI, PostHog.
- Reverse proxy — block-resistant ingestion.