https://docs.grainql.com/llms.txt (an index) and https://docs.grainql.com/llms-full.txt
(every page).
dist/index.d.ts and dist/types/index.d.ts of @grainql/tag 4.5.1,
and dist/index.d.ts plus dist/react/index.d.ts of @grainql/analytics-web 3.4.2. Read them
from node_modules before you generate code.Hard facts
- The tenant identifier in every call is the tenant alias that the dashboard shows at
https://grainql.com/dashboard, not the tenant UUID. The placeholder on this site isyour-tenant-id. - Grain Tag is the browser script:
https://tag.grainql.com/v4/your-tenant-id.js, or npm@grainql/tag. It collects page views, clicks, scroll depth, heatmaps, DOM snapshots, sessions, and attention without code. It has no remote configuration and no authentication strategy. - Analytics Web is the TypeScript SDK: npm
@grainql/analytics-web. It sends events and user properties, reads remote configuration, runs in browsers and in Node.js, and ships React hooks under@grainql/analytics-web/react. - Both packages are cookieless by default. The visitor ID rotates every day. A persistent ID is stored only after a consent call.
- Analytics Web batches events. The queue flushes every 5000 milliseconds or at 50 events,
whichever comes first.
flush()sends the queue now. - Analytics Web has three
authStrategyvalues:NONE(the default),SERVER_SIDEwithsecretKey, andJWTwithauthProvider.SERVER_SIDEsendsAuthorization: Chase <secret>. - The Query API base URL is
https://queryapis.grainql.com/v1/api/query. Every request carries anX-API-Keyheader. - The MCP server is at
https://grainql.com/api/mcp. It uses OAuth 2.1 with the scopesmcp:read,mcp:query, andmcp:investigate. It is read-only. - Every remote configuration value is a string.
getConfigreturnsstring | undefined, andgetAllConfigsreturnsRecord<string, string>. - In Grain Tag,
trackandidentifycalled beforeinitare queued and replayed afterinit. import { init, track, identify } from '@grainql/tag'has no side effects. Outside a browser,initreturns a no-op stub, so server-side rendering needs no guard.
Which package
Surface
Grain Tag, module exports of@grainql/tag. The script build exposes the same init,
getInstance, track, identify, and GrainTag on window.GrainTag.
GrainTagInstance.
GrainAnalytics class of @grainql/analytics-web.
createGrainAnalytics(config) returns the same class as new GrainAnalytics(config).
SendEventOptions is { flush?: boolean }. RemoteConfigOptions is
{ immediateKeys?: string[], properties?: Record<string, string>, userId?: string, forceRefresh?: boolean, currentUrl?: string }.
The types also export trackSystemEvent, getEphemeralSessionId, getCurrentPage,
getEventCountSinceLastHeartbeat, resetEventCountSinceLastHeartbeat, getActivityDetector,
getEffectiveUserIdPublic, and log as public methods. The tracking managers of the SDK call
them. Application code does not need them.
Analytics Web, exports of @grainql/analytics-web/react.
UseConfigOptions and UseAllConfigsOptions are both
{ forceRefresh?: boolean, immediateKeys?: string[], properties?: Record<string, string> }.
Read SDK reference and React hooks.
Configuration
GrainTagConfig, the argument of init in Grain Tag. The type file documents no defaults.
GrainConfig, the argument of new GrainAnalytics and createGrainAnalytics in Analytics Web.
Consent
Query API
Base URLhttps://queryapis.grainql.com/v1/api/query. Every request carries X-API-Key and,
for POST, Content-Type: application/json. The path parameter is the tenant alias.
429 with a Retry-After header in seconds. Custom plans with
higher limits exist. Read Query API for the error responses
and Export and query data for a task guide.
Mistakes to avoid
Using the tenant UUID instead of the tenant alias
Using the tenant UUID instead of the tenant alias
tenantId sends events to no tenant. Replace your-tenant-id with the alias.Putting a SERVER_SIDE secret in browser code
Putting a SERVER_SIDE secret in browser code
secretKey is a server credential. A bundle ships it to every visitor. In the browser, use
Grain Tag, or Analytics Web with NONE or JWT. Keep SERVER_SIDE in Node.js and read the
key from $GRAIN_SECRET_KEY.Expecting remote configuration from Grain Tag
Expecting remote configuration from Grain Tag
GrainTagInstance has no getConfig. Remote configuration, feature flags, and A/B variants
are Analytics Web features. Install @grainql/analytics-web for them.Expecting heatmaps from Analytics Web without enableHeatmapTracking
Expecting heatmaps from Analytics Web without enableHeatmapTracking
enableHeatmapTracking: true, or use
Grain Tag, which collects heatmaps and DOM snapshots without an option.Mixing the two SDK APIs in one file
Mixing the two SDK APIs in one file
init, track, identify, and consent.grant. Analytics Web has
createGrainAnalytics, grain.track, grain.login, and grain.grantConsent. A file that
imports both sends every event two times. Pick one package per surface.Forgetting flush() before a serverless function exits
Forgetting flush() before a serverless function exits
await grain.flush() before the return, or pass
{ flush: true } to track.Treating a configuration value as a boolean
Treating a configuration value as a boolean
getConfig('feature_enabled') returns 'true', not
true. Compare with === 'true'.Retrying on 429 without reading Retry-After
Retrying on 429 without reading Retry-After
429. Read the Retry-After header and wait that many seconds before the next request.Client checklist
Read the tenant alias from the dashboard
tenantId, in the script URL, or in the Query API path. Never the UUID.Pick one package per surface
Keep secrets on the server
secretKey and the Query API key come from environment variables in server code only.Name events in snake_case
signup_completed. Read
Name events.Call identify or login after sign-in
Flush before a short-lived process exits
await grain.flush() at the end of a serverless function, a script, or a test.Compare configuration values as strings
defaultConfigurations so the first render has a value.Do not generate
- Do not generate a consent banner that blocks tracking in the default mode. Both packages are cookieless by default and need no consent for that mode.
- Do not generate code that reads
window.grain. The script build exposeswindow.GrainTag. Analytics Web exposes nothing onwindowwhen it is imported from npm. - Do not generate an
apiUrlother than the default unless the user has one. - Do not generate a call to
grain.getConfigin Grain Tag code, or a call toconsent.grantin Analytics Web code. Each package has its own API. - Do not generate a Query API call from browser code. The API key is a server credential.
- Do not generate a method, an option, or an endpoint that is not in the tables on this page.