Snippets
Minimal copy-paste blocks for flags, configs, kill switches, experiments and i18n.
Minimal copy-paste blocks, grouped by the registry taxonomy. These are the same leaves the docs get op returns.
release
release / flags
Read the {{FLAG_KEY}} gate for the bound user. Assumes Configure() ran at startup — see Installation.
Read a flag
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetFlag(name) — name is the gate key; returns false if the gate is
// absent, disabled, or killswitched (never a user argument — it's bound).
if c.GetFlag("{{FLAG_KEY}}") {
// new behaviour
}Flag with an explicit fallback
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetFlagOr(name, def) — def is returned ONLY when the flag can't be
// evaluated (engine not ready, or the gate is absent); a gate that
// evaluates false returns false.
on := c.GetFlagOr("{{FLAG_KEY}}", true) // name; def returned only on can't-evaluate
_ = onrelease / configs
Read the {{CONFIG_KEY}} dynamic config (typed JSON value). Assumes Configure() ran at startup — see Installation.
Read a config
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetConfig(name) — name is the config key; returns (value any, ok bool).
// ok is false when the key is absent. Type-assert value to what you stored.
if cfg, ok := c.GetConfig("{{CONFIG_KEY}}"); ok {
m := cfg.(map[string]any) // configs are arbitrary JSON
_ = m["cta"]
}Config with an explicit fallback
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetConfigOr(name, def) — def is returned when the key is absent.
v := c.GetConfigOr("{{CONFIG_KEY}}", map[string]any{"cta": "Buy"}) // name; def
_ = vrelease / killswitches
Check whether the {{KILLSWITCH_KEY}} kill switch is engaged. Assumes Configure() ran at startup — see Installation.
Read a kill switch
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetKillswitch(name) — name is the kill-switch key; true means engaged
// (the feature is killed). Returns false if the switch is absent.
if c.GetKillswitch("{{KILLSWITCH_KEY}}") {
// feature is killed — short-circuit
}Read a named per-key switch
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetKillswitch(name, switchKey) — the optional switchKey selects a named
// per-key override (the dashboard "switches" feature). When that key has no
// override, it falls back to the kill switch's top-level value.
if c.GetKillswitch("{{KILLSWITCH_KEY}}", "eu") {
// killed for the "eu" variant
}release / experiments
Evaluate the {{EXPERIMENT_KEY}} experiment and track the {{SUCCESS_EVENT}} conversion. Assumes Configure() ran at startup — see Installation.
Evaluate and render the assigned group
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// GetExperiment(name, defaultParams) — name is the experiment key;
// defaultParams is returned as r.Params when the user isn't enrolled.
r := c.GetExperiment("{{EXPERIMENT_KEY}}", map[string]any{"color": "blue"})
if r.InExperiment {
p := r.Params.(map[string]any)
render(p["color"])
}Track the conversion
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// Track(event, props) — Client-only; the unit id is derived from the bound
// attributes (user_id, else anonymous_id). event is the metric event name;
// props are optional numeric/string fields. Fire-and-forget.
c.Track("{{SUCCESS_EVENT}}", map[string]any{"amount": 49}) // event; propsmetrics
metrics / track
Track a metric/conversion event from the bound Client. Metrics in the dashboard
are computed from these events. Assumes Configure() ran at startup — see
Installation.
Track an event
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
// Track(event, props)
// event — the event your metric is built on (required)
// props — optional payload; numeric/string fields you can sum/filter on in a
// metric (private attributes are stripped before egress)
c.Track("{{EVENT_NAME}}", map[string]any{"amount": 49, "currency": "usd"})Fire-and-forget (never blocks your response) and a no-op under
ConfigureForTesting / ConfigureForOffline. The unit is the bound user
(user_id, else anonymous_id); with no unit the call is a no-op.
Track without properties
// construct once per callsite (cheap; binds the user)
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_123"})
c.Track("{{EVENT_NAME}}", nil) // props are optional — pass nili18n
i18n / setup
The Go SDK is server-side: it emits the browser i18n loader tag (public client key) for the {{PROFILE}} profile. Translation rendering itself happens in the browser via the client SDK's t(). Assumes Configure() ran at startup — see Installation.
// I18nScriptTag is package-level — it runs off the global Configure(). Emit
// the returned tag in your document <head>.
// clientKey string the PUBLIC client key (NOT the server key)
// "{{PROFILE}}" string the locale profile to load (e.g. "en:prod")
// BootstrapTagOptions{} optional: AnonID, I18nProfile, BaseURL
tag := shipeasy.I18nScriptTag(clientKey, "{{PROFILE}}", shipeasy.BootstrapTagOptions{})
_ = tagi18n / render
There is no server-side t() in Go — translated labels are rendered in the browser by the client SDK once I18nScriptTag has loaded the {{PROFILE}} profile.
// Browser (client SDK), after the loader installs the {{PROFILE}} labels:
const label = shipeasy.t("checkout.cta");ops
ops / see
Report a caught, handled error (or a non-exception "violation") to Shipeasy with
See() — fire-and-forget, never panics into the request path. Package-level, so
it reports against the configuration from Configure. Assumes Configure() ran
at startup — see Installation.
Report a handled error
if err := charge(order); err != nil {
// CausesThe(subject) — what the error affects (e.g. "checkout")
// To(outcome) — the terminal: what you do about it; builds + fires once
shipeasy.See(err).CausesThe("checkout").To("use the backup processor")
fallbackCharge(order)
}Attach context with .Extras(...)
if err := charge(order); err != nil {
// Extras(map) — structured fields attached to the report (sanitized:
// string/number/bool only; private attributes stripped before egress).
shipeasy.See(err).
CausesThe("checkout").
Extras(map[string]any{"order_id": order.ID}).
To("use cached prices")
}Report a non-exception violation
// A bad state that isn't an error — the name is a STABLE fingerprint; put
// variable data in .Extras, never the name. .To() is the terminal.
shipeasy.SeeViolation("missing_invoice").
CausesThe("billing").
To("skip the dunning email")Mark an expected error — report NOTHING
if errors.Is(err, sql.ErrNoRows) {
// transmits nothing; .Because(...) / .Extras() are local-debug only
shipeasy.ControlFlowException(err).Because("a missing row is the empty-state path")
}Admin API client (optional) — `admin` module
The base SDK evaluates flags, configs, and experiments (Configure() + NewClient(user)). The Admin API client is a separate, optional surface for…
Agent skill
Installable LLM skill for the Go SDK (configure() + Client(user), evaluate, experiment + track, testing).