Web SDK Installation
Install the Prevenue Web SDK for supplemental browser events.
The Web SDK is a supplemental event source for browser-observable product moments such as activation, pricing intent, checkout starts, downgrade or cancel intent, team invites, and limit friction. Keep backend systems, Stripe, PostHog, Segment, or Direct API events as the primary source when they already provide cleaner account-level data.
Create a client
In Prevenue, open Settings → Integrations → Web SDK, create a client, and add the exact origins where the customer app runs. The client key is publishable and origin-limited, but it is shown only once so the install snippet can be copied safely.
Never place Direct API, PostHog, Segment, Stripe, or server ingest secrets in browser code.
Use SaaSFunnels MCP Server when a coding agent needs source-boundary context. The SaaSFunnels CLI validates Direct API, PostHog, and Segment payloads; the Web SDK remains the browser-safe path for visible intent and must not receive server ingest keys.
Install the script
Add the hosted script to the customer application and initialize it with the Web SDK client key.
<script>
window.prevenue = window.prevenue || [];
window.prevenue.push(["group", "acct_123"]);
window.prevenue.push(["init", {
clientKey: "<web_sdk_client_key>",
host: "https://app.prevenue.ai",
autoPage: false
}]);
window.prevenue.push(["track", "upgrade_clicked", {
plan: "growth",
source: "pricing"
}]);
</script>
<script async src="https://app.prevenue.ai/sdk/prevenue.js"></script>Identify accounts
Every useful revenue event needs a stable account identity. Call prevenue.group("acct_123", traits) once the account, workspace, company, or tenant is known. You can also pass account_id on individual track calls.
Accountless events are stored as setup diagnostics instead of becoming revenue signals.
Send account traits
Use prevenue.group(accountId, traits) to send the ordinary SaaS account facts Prevenue needs for account tracking and signal quality. Refresh these traits when the account signs up, changes plan, enters or exits trial, changes team size, or loads the authenticated app shell.
window.prevenue.group("acct_123", {
account_created_at: "2026-06-01T12:00:00.000Z",
plan: "starter",
is_in_trial: true,
trial_ends_at: "2026-06-28T12:00:00.000Z",
user_count: 7,
active_user_count: 6,
seat_count: 10
});Minimum useful traits:
| Fact | Preferred field names | Notes |
|---|---|---|
| Customer signup date | account_created_at, signup_at, or customer_created_at | This is the customer product signup date, not the time Prevenue first saw the account. |
| Login activity | Track user_logged_in or session_started | Include a stable user ID with identify or track options when available. |
| Plan and lifecycle | plan, plan_name, current_plan, account_status, or subscription_status | Keep values bounded and stable. |
| Trial state | is_in_trial, trial_started_at, trial_ends_at | Use as a fallback when Stripe is not connected. Stripe is authoritative for billing and trial state when connected. |
| Team and seats | user_count, active_user_count, seat_count, or member_count | Send counts only, not raw user lists. |
Track events
Start with explicit events that map to revenue semantics:
window.prevenue.track("user_logged_in", {
source: "app_shell"
});
window.prevenue.track("checkout_started", {
plan: "growth",
value: 1
});Generic page views are not treated as revenue signals by default. Use explicit names such as pricing_viewed, upgrade_clicked, cancel_flow_started, or team_member_invited when the page or action reflects intent.
Sparse Event KPI events
Prevenue does not need full clickstream telemetry to produce Event KPI analytics. Start with a small allowlist of account-scoped events that describe value, friction, expansion intent, and sentiment.
| Event family | Example names | Useful properties |
|---|---|---|
| High-value usage | feature_used, api_credits_used, report_exported, workflow_completed, generation_completed, sync_completed | feature_key, feature_area, is_key_feature, is_premium, value, quantity, usage_ratio, allowance, sentiment fields |
| Activation / first value | account_activated, first_value_completed, onboarding_completed | plan, feature, value, sentiment fields |
| Limit friction | limit_hit, quota_blocked, overage_prompt_viewed | usage_ratio, allowance, plan, value, sentiment fields |
| Product or support friction | sync_failed, setup_failed, support_needed | feature, error_code, severity, sentiment fields |
| Upgrade intent | pricing_viewed, upgrade_clicked, premium_feature_clicked, premium_feature_used, checkout_started | plan, current_plan, target_plan, feature_key, value, sentiment fields |
| Downgrade or cancel intent | downgrade_flow_started, cancel_flow_started | plan, reason_code, sentiment fields |
| Team expansion | team_member_invited, seat_added, role_assigned | quantity, role, plan, sentiment fields |
| Integration connected | integration_connected, oauth_connected, integration_configured | integration, provider, sentiment fields |
| Checkout outcome | checkout_started, checkout_completed, checkout_abandoned | plan, value, currency, sentiment fields |
These same event names and properties work for the Web SDK, Direct API, PostHog, and Segment. The source-specific wrapper can change, but the account identity, event name, timestamp, value fields, semantic intent, and sentiment fields should stay consistent.
Flag key features
Use key-feature fields on high-value usage, premium intent, or limit-friction events when the feature itself explains account health, expansion readiness, or churn risk. Do not create dynamic event names such as generation_feature_used or one event name per feature. Keep the event name stable, then describe the feature with bounded properties.
For Web SDK events, call prevenue.group(accountId, traits) before tracking, then send:
feature_key: stable machine name for the feature, such asgeneration,export,workflow, orapi.feature_area: stable product area, such asai,reporting,automation, orintegrations.is_key_feature:trueonly when the feature is part of the customer's core value path.is_premium:truewhen the feature is paid, gated, or upgrade-relevant.value,quantity,usage_ratio, orallowancewhen the action has measurable volume or usage pressure.
window.prevenue.group("acct_123", { plan: "starter" });
window.prevenue.track("feature_used", {
feature_key: "generation",
feature_area: "ai",
is_key_feature: true,
is_premium: true,
value: 1
});Use the Web SDK for browser-visible feature clicks, premium-feature intent, or UI friction the backend cannot see. Use Direct API instead when the backend can confirm completed usage, billable metering, export completion, workflow completion, quota calculation, or a durable setup milestone.
Sentiment fields
Sentiment is optional and separate from the event family. Missing sentiment is stored as unknown, not neutral; use neutral only when the customer action explicitly carries neutral sentiment.
Send sentiment only when the browser action has a bounded, defensible signal. If sentiment is omitted, Prevenue may infer a mapping default from the event name, semantic type, event kind, and bounded property keys. That mapped default is reviewable in the Events page and fills future events only when payload sentiment is missing or unknown.
window.prevenue.track("api_credits_used", {
value: 250,
usage_ratio: 0.82,
allowance: 300,
feature_key: "generation",
feature_area: "ai",
is_key_feature: true,
sentiment: "negative",
sentiment_score: -0.6,
sentiment_confidence: 0.8,
sentiment_source: "explicit"
});Accepted sentiment fields:
| Field | Values |
|---|---|
sentiment | positive, neutral, negative, unknown |
sentiment_score | Number from -1 to 1 |
sentiment_confidence | Number from 0 to 1 |
sentiment_source | explicit, inferred, ai, integration, unknown |
Do not send free-text feedback, support transcripts, chat messages, form fields, or raw customer comments as sentiment context. Send a bounded label, score, confidence, and source instead.
KPI coverage
Each Event KPI improves with a few specific event families. More volume helps, but variety and account identity matter more than tracking every click.
| KPI | Minimum useful coverage |
|---|---|
| Sentiment Trends | Any revenue-relevant event family with sentiment fields across 7, 14, or 30 day windows |
| Sentiment-Weighted Usage | High-value usage events with value, quantity, or usage_ratio, plus optional sentiment |
| Revenue-Sentiment Divergence | Usage, checkout, upgrade, downgrade, or cancel intent events combined with billing or plan context |
| Friction Load | Limit, support, setup, sync, checkout, or payment-friction events plus value events for comparison |
| Expansion Surface Area | Upgrade intent, top-ups, team expansion, integration connected, usage pressure, and positive sentiment |
| Account Momentum Quality | A mix of usage, activation, expansion, friction, and sentiment events over trailing windows |
As a rule of thumb, one or two isolated events are diagnostic only. Three or more account-scoped events in a 14 day window can become directional. Five or more relevant events in 30 days, especially across two or more event families, can support usable KPI confidence. Low-volume accounts should still show sample size and low-evidence states instead of being forced into a strong classification.
See Event KPI Signals for the canonical KPI definitions and account filter fields.
Source-compatible examples
Direct API payloads can send the normalized field names directly:
{
"account_id": "acct_123",
"event_id": "evt_usage_001",
"event_name": "api_credits_used",
"timestamp": "2026-06-20T15:00:00.000Z",
"value": 250,
"usage_ratio": 0.82,
"sentiment": "negative",
"sentiment_score": -0.6,
"sentiment_confidence": 0.8,
"sentiment_source": "explicit"
}PostHog and Segment should forward the same business fields inside properties while keeping a stable account or group identity:
{
"event": "api_credits_used",
"properties": {
"account_id": "acct_123",
"account_created_at": "2026-06-01T12:00:00.000Z",
"active_user_count": 6,
"is_in_trial": true,
"plan": "starter",
"seat_count": 10,
"trial_ends_at": "2026-06-28T12:00:00.000Z",
"value": 250,
"usage_ratio": 0.82,
"sentiment": "negative",
"sentiment_score": -0.6,
"sentiment_confidence": 0.8,
"sentiment_source": "integration"
},
"timestamp": "2026-06-20T15:00:00.000Z"
}{
"type": "track",
"event": "team_member_invited",
"groupId": "acct_123",
"userId": "user_456",
"properties": {
"quantity": 2,
"sentiment": "positive"
},
"timestamp": "2026-06-20T15:00:00.000Z"
}Data safety
The SDK sends event names, timestamps, URL path/referrer context, account/user identifiers, and the properties you provide. Do not send form values, emails, session tokens, API keys, cookies, authorization headers, arbitrary route changes, every button click, or free-text support content.
Verify setup
After installation, send one event from an allowed origin and check Settings > Integrations > Web SDK and Events. A valid account-scoped event should appear as source web_sdk. If the event is missing account identity, Prevenue will show a rejected diagnostic row with setup guidance.