From install to evidence.
Use the SDK, raw HTTP or the MCP server. They share one schema, one permission model and the same evidence behind every answer.
Quickstart
Create a product and a key
In Setup, add a product. Browser project keys (
ahl_pub_…) are origin-scoped, capped and revocable; server API keys stay secret.Send data, or paste a URL
Install the SDK for events, replay, flags and errors. For uptime alone, paste a URL in Status pages: no code is needed.
Check it arrived
Setup confirms the environment, consent, masking, identity and the first events. Choose one outcome, such as signup, so later answers have something to measure against.
Want to look around first? Add the demo product to see every page with sample data.
Install the SDK
@sansavision/apphelm 0.5.0 is on npm. One package covers Node, the browser, React and React Native; each entry point is loaded only if you import it, so the browser core stays small.
npm install @sansavision/apphelm0.5.0| Entry point | What it has | Runs in |
|---|---|---|
@sansavision/apphelm | The Node client: products, metrics, flags, capture, deploys, heartbeats, cron check-ins and source maps, plus the apphelm CLI | Server |
@sansavision/apphelm/browser | Consent-gated analytics, autocapture, web vitals, flags, error capture and session replay | Browser |
@sansavision/apphelm/react | ApphelmProvider, hooks for flags and tracking, an error boundary and YouSaid's components. Needs React 19 or later | Browser |
@sansavision/apphelm/react-native | track, screen, flags and exceptions in pure JS, with no native modules. Identity stays on your server | App |
@sansavision/apphelm/feedback | Optional YouSaid in-app feedback that carries Apphelm's ids | Browser |
@sansavision/apphelm/server | createYouSaidIdentityToken. It takes your YouSaid signing secret, so never import it in a browser | Server only |
Upgrading to 0.5? The React entry now needs React 19 or later, and a ^0.4.0 range does not pick 0.5 up: install @sansavision/apphelm@^0.5.0.
Browser
Collection begins disabled. After analytics consent, page views and optional autocapture send the path, referrer, campaign and click positions, never input values or element text. Flags are fail-closed. The replay module is loaded only after both analytics and replay consent, records masked layout and interaction, and blocks authentication, billing, payment and admin routes by default.
import { createBrowserSdk } from "@sansavision/apphelm/browser";
const analytics = createBrowserSdk({
key: "ahl_pub_…",
workspaceId: "org_…",
productId: "prd_…",
replay: { consentPolicyVersion: "consent_v1", sampleRate: 0.25 }
});
// Read this choice from your consent manager.
analytics.setConsent({ analytics: true, replay: true });
analytics.page();
analytics.track({ name: "signup_completed" });
if (analytics.isEnabled("new-checkout")) renderNewCheckout();
analytics.captureException(error);React
The optional /react entry needs React 19 or later. The provider creates the client in an effect, so server rendering builds no client and sends nothing; flags stay off until the bootstrap settles. ApphelmErrorBoundary reports render errors with the component names.
import { ApphelmProvider, useFeatureFlag, useTrack } from "@sansavision/apphelm/react";
<ApphelmProvider options={{ key: "ahl_pub_…", workspaceId: "org_…", productId: "prd_…" }}>
<App />
</ApphelmProvider>;
function Checkout() {
const newCheckout = useFeatureFlag("new-checkout");
const track = useTrack();
return <button onClick={() => track({ name: "checkout_started" })}>
{newCheckout ? "Pay now" : "Checkout"}
</button>;
}Node and the CLI
The server client uses abortable requests and typed errors. Pass your user id as the browser's distinctId and to capture, and server events join that person's browser events. The apphelm CLI reports deploys and status from a build pipeline.
import { Apphelm } from "@sansavision/apphelm";
const apphelm = new Apphelm({ apiKey: process.env.APPHELM_API_KEY });
const products = await apphelm.listProducts();
await apphelm.capture({ distinctId: user.id, event: "subscription_paid" });# Needs events:write. The commit comes from GITHUB_SHA and similar variables.
APPHELM_API_KEY=… npx apphelm deploy prd_… 1.4.2 production
# Needs status:write. Reports to the product's status page; not a billed event.
APPHELM_API_KEY=… npx apphelm heartbeat prd_… degraded "Checkout is slow"In-app feedback with YouSaid
New in 0.5.0: in-app feedback, the reply inbox and release receipts come from YouSaid, as an optional part of the SDK. It builds on YouSaid's own packages, installed as dependencies, and adds Apphelm's ids to every signal, so a YouSaid thread links back to the person and the session. Only ids and hashes are sent, never an email or a name, and the person and session hashes only with analytics consent. The browser core loads none of it.
// Server only: the signing secret never reaches the browser.
import { createYouSaidIdentityToken } from "@sansavision/apphelm/server";
const token = await createYouSaidIdentityToken(
{ sub: user.id, org_id: process.env.YOUSAID_ORG_ID, product_id: process.env.YOUSAID_PRODUCT_ID },
process.env.YOUSAID_SIGNING_SECRET,
{ keyId: process.env.YOUSAID_KEY_ID },
);import { createFeedback } from "@sansavision/apphelm/feedback";
// analytics is the createBrowserSdk client. Mint a fresh token for each call.
const feedback = createFeedback({ token: () => fetch("/api/yousaid-token").then((r) => r.text()), analytics });
await feedback.sendSignal({ kind: "bug", title: "Export fails", body: "The CSV export spins forever." });import { AppHelmFeedbackProvider, Inbox, YouSaidLauncher } from "@sansavision/apphelm/react";
<AppHelmFeedbackProvider token={mintToken}>
<YouSaidLauncher label="Feedback" />
<Inbox />
</AppHelmFeedbackProvider>;| @sansavision/apphelm | @sansavision/yousaid | @sansavision/yousaid-react | @sansavision/yousaid-server |
|---|---|---|---|
| 0.5.x | ^0.2.0 | ^0.2.0 | ^0.2.0 |
Swift, Kotlin and Python
Every SDK carries the same version number, so it is always clear which releases go together.
- Swift (iOS and macOS)
- Available · 0.5.0
A Swift package using URLSession only, with crash reporting and release health. Add it with Swift Package Manager:
.package(url: "https://github.com/Sansa-Organisation/apphelm-swift.git", from: "0.5.0") // target dependency: .product(name: "Apphelm", package: "apphelm-swift") - Kotlin (JVM)
- Coming soon to Maven Central
A plain-JVM Kotlin client for events, flags and exceptions. It is not a native Android SDK: you supply storage and threading. Until it is published, Android apps can use the React Native entry.
- Python
- Coming soon to PyPI
A standard-library-only client for flags, capture, exceptions, tracing and cron check-ins.
REST API v1
Bearer authentication with a scoped API key, cursor pagination, idempotency keys on writes, and correctness metadata with every metric. The OpenAPI 3.1 document describes every route.
Least privilege. Browser keys are never accepted as server credentials. A key shipped in an app binary should hold events:write only, and be treated as public and revocable.
Connect the remote MCP server
Use an Apphelm API key as a Bearer token. A workspace key sees only its own workspace. Tools read products, metrics, insights, sessions, incidents, flags and customer intelligence; Beam questions go through SansaAI and use AI credits; draft tools store proposals for a person to review.
{
"mcpServers": {
"apphelm": {
"url": "https://apphelm.dev/mcp",
"headers": {
"Authorization": "Bearer ${APPHELM_API_KEY}"
}
}
}
}Human confirmation stays mandatory. Draft tools never create issues, deploy code or change production. Nothing is launched or sent.
Uptime checks and status pages
Create a page in Status pages and paste any public HTTPS page or health endpoint. Apphelm checks it straight away and every five minutes after that, with no monitoring code. That HTTPS check is the product's uptime check; a status page without one uses none. Visitors can subscribe to email updates, and the page shows 90 days of history.
For private systems and richer health signals, report status yourself with a signed heartbeat, and embed a compact status card anywhere.
curl -X POST https://apphelm.dev/api/v1/status/heartbeat \
-H "Authorization: Bearer $APPHELM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"productId":"prd_…","status":"operational","responseTimeMs":214}'<iframe
src="https://apphelm.dev/status/your-page/embed"
title="Service status"
loading="lazy"
sandbox="allow-popups"
style="width:100%;height:148px;border:0;border-radius:16px">
</iframe>Public by design. Display names and status messages are customer-visible. Check targets, workspace ids and telemetry stay private.
Import a PostHog export
In the app, open Settings, then Import from PostHog. Choose a product and upload one export file: PostHog's batch export of events as JSON Lines, gzipped or not, up to 50 MB and 100,000 rows. You get a full preview first: events by name, and every row that would be left out with its reason. Nothing is written until you confirm, and an import can be undone for 30 days.
Events keep their own dates, within what your plan keeps. $pageview is stored as page_viewed. The import brings in events only: people are not imported, so send them from your own server with identify. IP addresses, user agents, page content and PostHog's own properties are never imported; nor are exceptions, recordings, cohorts, dashboards or flag definitions.
{"uuid":"018f3b5a-…","event":"$pageview","distinct_id":"user-1",
"timestamp":"2026-09-01T10:00:00Z",
"properties":{"$current_url":"https://app.example.com/pricing","plan":"builder"}}
{"uuid":"018f3b5b-…","event":"signup_completed","distinct_id":"user-1",
"timestamp":"2026-09-01T10:05:00Z",
"properties":{"plan":"builder","$set":{"plan":"builder"}}}Imported events do not use your monthly event allowance. They are counted separately, up to 250,000 a day, and never trigger an alert, a webhook or an email.
Try it on the demo product
An owner or admin can add one demo product from Setup. It is called “Demo store (sample data)”, carries a Sample data badge and banner, and fills every page with 60 days of generated data: events, customers, issues, flags, an experiment, session replays, surveys and an uptime check.
Sample data shows only while the demo product is selected. It is kept out of billing, usage, plan limits and your own numbers. You can move a sample insight or triage a sample issue; creating something new on it is refused. Remove it from Setup and every sample row goes with it.
Privacy boundaries
- Consent first
- Analytics and replay are off until an explicit choice. Replay loads separately, stores no text or field values, and blocks sensitive routes by default.
- Evidence first
- Beam returns its classification, confidence, evidence, counter-evidence, queries and data-quality warnings with every answer.
- Least privilege
- Server secrets stay in Wrangler secrets. Browser keys are not accepted as server credentials. MCP uses the same scoped API boundary.