Backends
Go
Go analytics with Stickybeak starts by adding its script to your rendered pages; this guide shows you where it belongs and how to track page views, goals and purchase revenue.
Add the script
Set the site ID
Set
STICKYBEAK_SITE_IDin your production environment only. Copy the ID from Settings in the dashboard.Pass it to every page
Wrap your page data in a struct that carries the site ID, and render through one helper:
var stickybeakSite = os.Getenv("STICKYBEAK_SITE_ID") // empty outside production type Goal struct { Name string Props map[string]any } type Page struct { StickybeakSite string Goal *Goal Data any } func render(w http.ResponseWriter, r *http.Request, name string, data any) { page := Page{StickybeakSite: stickybeakSite, Goal: takeGoal(w, r), Data: data} if err := tmpl.ExecuteTemplate(w, name, page); err != nil { log.Print(err) } }Add it to your head template
{{define "head"}} <script>window.stickybeak = window.stickybeak || function () { (window.stickybeak.q = window.stickybeak.q || []).push(arguments); };</script> {{if .StickybeakSite}} <script defer data-site="{{.StickybeakSite}}" data-domain="example.com" src="https://app.usestickybeak.com/_cfw/s.js" ></script> {{end}} {{with .Goal}} <script>window.stickybeak({{.Name}}, {{.Props}});</script> {{end}} {{end}}
Check it's working
Publish first, then follow Verify your install.
Track goals
Give any button or link a data-goal attribute. See Custom goals.
<button data-goal="start_trial" data-goal-plan="pro">Start trial</button>
Fire a goal after a redirect
The handler that saves a signup or confirms a payment usually redirects.
const goalCookie = "sb_goal"
func setGoal(w http.ResponseWriter, g Goal) {
b, _ := json.Marshal(g)
http.SetCookie(w, &http.Cookie{
Name: goalCookie, Value: base64.RawURLEncoding.EncodeToString(b),
Path: "/", MaxAge: 60, HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode,
})
}
func takeGoal(w http.ResponseWriter, r *http.Request) *Goal {
c, err := r.Cookie(goalCookie)
if err != nil {
return nil
}
http.SetCookie(w, &http.Cookie{Name: goalCookie, Path: "/", MaxAge: -1})
b, err := base64.RawURLEncoding.DecodeString(c.Value)
if err != nil {
return nil
}
var g Goal
if json.Unmarshal(b, &g) != nil {
return nil
}
return &g
}
mux.HandleFunc("POST /signup", func(w http.ResponseWriter, r *http.Request) {
user, err := createUser(r)
if err != nil {
// ...
return
}
setGoal(w, Goal{Name: "signup", Props: map[string]any{"plan": user.Plan}})
http.Redirect(w, r, "/welcome", http.StatusSeeOther)
})
Inside a <script>, html/template writes {{.Name}} as a quoted JavaScript string and {{.Props}} as a JSON object, escaped so nothing can break out of the tag.
If you already use a session package such as gorilla/sessions or scs, use its flash or pop-on-read helpers instead of the cookie.
Track purchases
setGoal(w, Goal{Name: "purchase", Props: map[string]any{
"revenue": order.Total, "currency": order.Currency, "order_id": order.ID,
}})
With templ, render the same tags in your layout component.
See Revenue.
If it isn't working
- If
data-siteis empty, the environment variable is not reaching the process.
See Troubleshooting.