Web2Wave JS SDK for external websites

Drop a lightweight script on any checkout or thank-you page to send events back to web2wave. Conversion events are forwarded to Meta, TikTok, and other ad networks via server-side APIs — no pixels on the external site.

The Web2Wave JS SDK is a small browser script you add to websites that are not hosted on web2wave (your own checkout, a third-party payment page, a thank-you page, a membership site).

From that page you can send conversion events back to web2wave. web2wave then:

  • Stores them on the same user who started the quiz (user_id)
  • Forwards them server-side to Meta Conversions API, TikTok Events API, and other connected ad networks

Amplitude, PostHog, and Mixpanel are not in this path. Those tools only receive browser events from the quiz / paywall itself. The SDK posts to web2wave’s server, and web2wave does not replay those server events into Amplitude / PostHog / Mixpanel.

You do not install a Meta Pixel, TikTok Pixel, or Google tag on the external website. Pixels and access tokens stay in Project → Analytics. The SDK only talks to web2wave; web2wave talks to the ad networks from the server.

This is the typical flow the SDK is built for:

  1. The user completes a web2wave quiz.
  2. They leave to an external payment page (your checkout, a PSP hosted page, a custom store).
  3. After a successful charge, the thank-you page calls web2wave.purchase(...) (or web2wave.track('Subscribe', ...)).
  4. web2wave attributes the conversion to the original quiz session and sends it to Meta / TikTok / Google as a Conversion API event.
📘

Inside a web2wave quiz or paywall, keep using window.w2w. This SDK is only for external pages. For native apps, see the mobile SDKs.


Why use it

Without the SDKWith the SDK
Payment happens off-site, so web2wave never sees PurchaseThe thank-you page reports Purchase / Subscribe back to web2wave
Meta/TikTok pixels must be installed (and allowed) on the checkout domainNo ad pixels on the checkout domain — CAPI is sent from web2wave servers
Browser blockers, ITP, and missing cookies break attributionThe same user_id from the quiz is sent with the event, so the funnel stays in one profile
You cannot optimize Meta/TikTok campaigns for off-site checkoutsStandard conversion events still train the ad accounts

Pixels configured in web2wave (with an Access Token for server events) are enough. See Analytics Integration Guide to connect Meta, TikTok, Google, Snap, and others.


Prerequisites

  1. Pixels / CAPI already set up in Project → Analytics (Pixel ID + Access Token for Meta and TikTok). Browser pixels on the quiz are optional for this flow; server events are what matter for the off-site conversion.
  2. Your project ID — the slug from Project Settings (project.project_id). It is the same value used in https://PROJECT_ID.web2wave.com.
  3. The web2wave user_id of the person who started the quiz. Pass it to the external page in the URL (see Identify the user).

Install

Load the SDK, then call init with your project slug:

<script src="https://app.web2wave.com/js/sdk/web2wave-sdk.min.js?v=1.0.0"></script>
<script>
  web2wave.init({
    projectId: 'YOUR_PROJECT_ID',
    apiBase: 'https://app.web2wave.com'
  });
</script>

Or pass the same values on the script tag (no init() call):

<script
  src="https://app.web2wave.com/js/sdk/web2wave-sdk.min.js?v=1.0.0"
  data-project-id="YOUR_PROJECT_ID"
  data-api-base="https://app.web2wave.com"
></script>
📘

Always set apiBase to https://app.web2wave.com. Put the script before init / purchase so web2wave already exists.


Identify the user

Every track / purchase / setProperty call requires a web2wave user_id. If it is missing, the SDK logs a warning and does not send the request.

Resolution order:

  1. userId passed to init() / setUserId() with override (default after setUserId)
  2. Query parameter — ?user_id=... (name configurable via userIdParam)
  3. userId from init() without override
  4. window.user_id if the page already defines it
  5. Value stored from a previous visit (w2w_user_id cookie / storage)

Pass user_id from the quiz

When you redirect from a quiz or paywall to the external site, append USER_ID to the URL:

https://checkout.example.com/pay?user_id=USER_ID

On the checkout page the SDK reads user_id automatically and persists it (cookie by default, 356 days, SameSite=Lax). Later pages on the same domain — for example /thank-you — still know who the user is.

If your links already use a different param (the paywall recipe uses web2wave_user_id), tell the SDK:

web2wave.init({
  projectId: 'YOUR_PROJECT_ID',
  apiBase: 'https://app.web2wave.com',
  userIdParam: 'web2wave_user_id'
});

Or set it in code:

web2wave.setUserId('USER_ID_FROM_QUIZ');
// alias:
web2wave.identify('USER_ID_FROM_QUIZ');

Optional context from the URL is also picked up: quiz_id, quiz_version, paywall_id, paywall_version. Include them on the checkout link if you want those fields on off-site events.

See Redirect to an external paywall after price selection for wiring the paywall CTA.


Send conversion events

Purchase (most common)

purchase is a shortcut for track('Purchase', ...). Meta and TikTok treat Purchase as a standard conversion event and can optimize campaigns on it.

web2wave.purchase('29.99', {
  currency: 'USD',
  value: '29.99',
  price_id: 'price_123',
  subscription_id: 'sub_456',
  eventID: web2wave.getUserId() + '_Purchase_sub_456'
});

The first argument is the numeric/string value. It is copied into both event_value and event_properties.value.

Any event

web2wave.track('Subscribe', {
  currency: 'USD',
  value: '29.99',
  price_id: 'price_123'
});

web2wave.track('StartTrial', { currency: 'USD', value: '0' });
web2wave.track('InitiateCheckout', { currency: 'USD', value: '29.99' });
web2wave.track('Lead');

Use the same event names as the quiz (see Analytics Events). Names that map to standard ad-network events are forwarded to CAPI:

SDK / web2wave eventMetaTikTok
PurchasePurchasePurchase
SubscribeSubscribeSubscribe
StartTrialStartTrialStartTrial
InitiateCheckoutInitiateCheckoutInitiateCheckout
CompleteRegistrationCompleteRegistrationCompleteRegistration
AddPaymentInfoAddPaymentInfoAddPaymentInfo
PageViewViewContentViewContent
Other namesCustom eventForwarded

Pass currency + value on money events so ROAS reporting works.

eventID (for example userId + '_' + eventName + '_' + orderId) is used for Meta deduplication. Set it when the same conversion might also be sent from a quiz page or a webhook.

Automatic PageView

web2wave.init({
  projectId: 'YOUR_PROJECT_ID',
  apiBase: 'https://app.web2wave.com',
  autoPageView: true
});

Or data-auto-pageview="true" on the script tag.


End-to-end example: quiz → external checkout → Purchase

1. Paywall / quiz — send the user to your checkout with their web2wave id:

https://pay.example.com/checkout?user_id=USER_ID&quiz_id={quiz_id}

2. Thank-you page — after the PSP confirms the charge:

<script src="https://app.web2wave.com/js/sdk/web2wave-sdk.min.js?v=1.0.0"></script>
<script>
  web2wave.init({
    projectId: 'YOUR_PROJECT_ID',
    apiBase: 'https://app.web2wave.com'
  });

  // user_id is taken from ?user_id=... or the w2w_user_id cookie
  var params = new URLSearchParams(window.location.search);
  var amount = params.get('amount') || '29.99';
  var orderId = params.get('order_id') || String(Date.now());
  var userId = web2wave.getUserId();

  web2wave.purchase(amount, {
    currency: 'USD',
    value: amount,
    order_id: orderId,
    eventID: (userId || 'unknown') + '_Purchase_' + orderId
  });
</script>

What web2wave does next (no extra code on your site):

  1. The event is stored for that user_id (cabinet funnel analytics and UTM report).
  2. If Meta CAPI is enabled, a Purchase event is sent to Events Manager with enhanced matching (email / external_id when web2wave already has them from the quiz).
  3. The same happens for TikTok, Google, and other ad networks you connected — using the tokens in Project Settings, not tags on pay.example.com.

These events are not sent to Amplitude, PostHog, or Mixpanel.

To also create a subscription in the cabinet (emails, customer portal, webhooks), call POST /api/subscription from your backend in addition to the SDK event. The SDK covers cabinet analytics + ad conversions (CAPI); the subscription API covers billing records.


User properties

Attach extra fields to the same user profile:

web2wave.setProperty('plan', 'yearly');

web2wave.setProperties({
  email: '[email protected]',
  plan: 'yearly',
  checkout_provider: 'custom'
});

Email collected on the quiz is already on the profile and is used for Meta/TikTok enhanced matching. Setting it again on the thank-you page is optional.


init options

OptionDefaultDescription
projectIdRequired. Project slug (project.project_id).
apiBaseAlways https://app.web2wave.com.
userIdfrom URL / storageweb2wave user id.
userIdParam'user_id'Query parameter to read the user id from.
userIdOverridefalseIf true, userId from config wins over the URL. setUserId() sets this to true.
useCookiestruePersist user_id and first URL in a cookie. If false, falls back to storage.
storage'session''session', 'local', or 'memory' when cookies are off.
persistUserIdtrueWrite w2w_user_id to storage.
persistInitialUrltrueRemember the first page URL (w2w_initial_url) and send it with events.
autoPageViewfalseSend a PageView event on init.
debugfalseLog [web2wave] messages to the console.
quizId / paywallId / versionsfrom URLAttached to every event when present.

Script data attributes (kebab-case → camelCase): data-project-id, data-api-base, data-user-id, data-user-id-param, data-use-cookies="false", data-storage, data-debug="true", data-auto-pageview="true".


Methods

All methods except getUserId return a Promise once the SDK is initialized.

init(options) / init(projectId)

Call this after the SDK script has loaded, before track / purchase. Not needed if you used data-project-id on the script tag.

getUserId()

Returns the resolved user id, or null.

setUserId(userId, options) / identify(userId, options)

web2wave.setUserId('abc123');
web2wave.setUserId('abc123', { persist: true, override: true });
  • persist (default true) — store in cookie/storage
  • override (default true) — ignore a different user_id in the URL

track(eventName, properties, options)

Sends POST /api/analytic/event/event_log.

options (all optional): eventValue, url, quizId, paywallId, paywallVersion.

purchase(value, properties, options)

Same as track('Purchase', ...), with value applied as the event value.

setProperty(name, value) / setProperties({ ... })

POST /api/analytic/user/property_set and .../properties_set_bulk.

enableCookies(options)

Turn cookie persistence on after init (for example after the user accepts a cookie banner).

web2wave.enableCookies();

Debugging

  1. init({ debug: true }) and watch the console for [web2wave] POST /api/analytic/event/event_log.
  2. Confirm web2wave.getUserId() is the same id as in the quiz (Cabinet → user, or the user_id query param).
  3. In web2wave, open Log of events sent using Conversion API and filter by user_id — the off-site Purchase should appear next to quiz events. Details: Advanced analytics.
  4. Meta Events Manager / TikTok Events Manager will show a server (CAPI) event, not a browser pixel hit from pay.example.com. That is expected.

Common issues:

SymptomCause
Warning user_id is missingCheckout URL has no user_id (or your custom userIdParam), and nothing is in storage.
Warning projectId is requiredinit was not called, or data-project-id is empty.
Event in web2wave but not in MetaAccess token / Conversion Events settings in Project → Analytics; or the event name is not in the CAPI allow-list.
Duplicate Purchase in MetaSend a stable eventID and keep Send conversion event only once enabled.
CORS / failed fetchapiBase must be https://app.web2wave.com.

Related