Core concepts

A short tour of UserGist's shared building blocks and its two product areas: Engage and Customer Portal.

Mental model

A workspace owns your team, apps, and company portal. Each app owns its users, events, audiences, Engage campaigns, and Customer Portal content. Engage uses SDKs to reach users inside your product; the portal publishes a destination customers can visit independently.

Workspace

The top-level container. A workspace owns:

  • A team (the humans, with roles)
  • A billing relationship (plan, usage, invoices)
  • One or more apps (your products / environments)
  • A Customer Portal with one company address and spaces for included apps

You typically have one workspace per company. Create more if you have distinct legal entities or strict data separation requirements.

App

An app is where your end-users live. Concretely it owns:

  • Write keys that authenticate your SDK
  • Push credentials (APNs .p8 for iOS, FCM service-account JSON for Android)
  • Users, events, segments, prompts, surveys, in-app messages, push campaigns, feature requests, analytics
  • Roadmap items, help articles and collections, changelog entries, and support conversations for its portal space

Most teams use separate apps per environment: Acme Production and Acme Staging. Builds for multiple platforms can share one app when they should use the same audience, campaigns, and analytics. Split iOS, Android, React Native, or Flutter into separate apps only when you want independent data, credentials, campaigns, or key rotation.

App overview showing the app switcher and Engage and Customer Portal navigation.
The sidebar app card switches apps and opens workspace controls.

User

A user is anyone who has opened your app while the SDK is initialised. Two states:

StateWhenStable ID
AnonymousBefore you call identifyanonymous_id (generated and stored locally)
IdentifiedAfter identify(userId, props, subjectToken)Your user_id (e.g. your DB primary key)

When you identify, userGist links the anonymous device session to the user ID. All prior anonymous events get retro-attributed.

Portal participants are a separate identity source. Reading public pages needs no sign-in; submitting requests, voting, and support require email verification. The portal creates app-scoped portal-origin identities and does not automatically merge them with SDK users by email. Dashboard members are your team, rather than these end-users.

// Anonymous: events get bucketed under an anonymous_id
UserGist.track('app_opened')
 
// Mint this token on your authenticated backend.
const { subjectToken } = await yourBackend.getUserGistSubjectToken()
 
// Now identified — same device, same user from here on.
await UserGist.identifyAsync('user_42', { plan: 'pro' }, subjectToken)
UserGist.track('checkout_completed', { amountUsd: 49 })
Calling `reset()` rotates the anonymous ID

Use UserGist.reset() on logout. It clears the cached user, generates a fresh anonymous_id, and prevents two accounts on the same device from being conflated.

Event

An event is a behavioural fact: user X did Y with these properties at time T.

UserGist.track('subscription_upgraded', {
  fromPlan: 'trial',
  toPlan: 'pro',
  monthlyUsd: 19,
})

Events are queued client-side and flushed in batches (every 15 s by default, or when the queue hits the batch size). They're stored in ClickHouse for analytics and used by the targeting engine to decide who's eligible for a campaign.

Two kinds of properties:

  • User properties (set on the user, persist across sessions) — sent via identify.
  • Event properties (specific to one event) — sent as the second argument to track.

See Features → Events for the schema registry, which lets you declare each event up-front and validate at ingest.

Segment

A segment is a reusable audience, defined by a DSL of property matchers and event-behaviour matchers.

Examples:

  • Power users — plan = 'pro' AND count(event = 'session_started', last 7 days) >= 5
  • Trial day 3 — count(event = 'trial_started', all time) >= 1 AND days_since(event = 'trial_started') = 3
  • Churn risk — plan = 'pro' AND count(event = 'session_started', last 14 days) <= 1

Segments are evaluated:

  • Server-side when scheduling campaigns or computing rosters.
  • Client-side by the SDK to decide instantly which prompt/in-app to show, using the same evaluator (@usergist/sdk-core/evaluateSegment). That's how surveys can fire immediately on an event without a network round-trip.

See Features → Segments for the full DSL.

Engage

Feedback prompts, surveys, in-app messages, and native push are the engagement channels. They share three building blocks:

  1. Targeting — a segment that decides who.
  2. Trigger — an event, a schedule, a deep-link, or on-demand.
  3. Content — what to render or send.
ChannelWhat it is
PromptSingle-question feedback (NPS, rating, thumbs). Fires inline on an event.
SurveyMulti-step questionnaire with branching, save-resume, deep-link.
In-app messageModal, slide-up or full-screen takeover with CTA buttons.
PushAPNs / FCM notification, scheduled or event-triggered.

Every channel writes a response/delivery record back into userGist, which feeds analytics and unlocks lifecycle hooks like onResponse.

Customer Portal

The Customer Portal is your company's public home for customer ideas, progress, releases, and help. Set it up independently of SDK installation, then include the apps customers should visit.

ResourcePurpose
Feature requestA customer idea submitted through the portal or an SDK, with votes, status, and a team response
Roadmap itemTeam-created work with its own progress and optional links to requests
Changelog entryA product release note with a date, category, content, and related work
Help article and collectionA published answer and the topic that organizes it
Support conversationA private customer thread, when support is enabled

Portal publication has separate layers: include the app, publish the company portal, and publish the individual content. A request's SDK visibility and portal visibility are independent. Articles and changelog entries keep private drafts alongside published snapshots; saving a published roadmap item updates it directly.

How the two areas connect

An SDK request can become a public idea after your team publishes it. A roadmap item can link that request. A release note can link the shipped work. To announce the release inside your app, create a separate Engage message or push campaign. Publishing portal content does not create a campaign or automatically merge identities.

Write key

The credential that lets the SDK talk to the ingest API. It is per-app, environment-labelled, rotatable, and shown in plaintext exactly once. The API uses it to route traffic to the correct workspace and app. It does not choose which SDK runs—the package installed by the developer already determines that.

Write keys are client identifiers and are expected to be extractable from a mobile binary. They cannot prove a product user's identity or access dashboard data. See Admin → Write keys for rotation, scoping and rate limits.

userGist treats consent as a first-class input. You pass it via setConsent({ analytics, feedback, push, survey }) and the SDK gates each subsystem accordingly. No consent? No events queued.

await UserGist.setConsent({
  analytics: true,
  feedback: true,
  push: false,
  survey: true,
})

See Guides → GDPR & consent for the recommended flow.

What's next