Embedded Wallet
Embedded Wallet: Analytics
Forward embedded wallet product telemetry from proxy.analytics to GA4 or your analytics stack — subscribe in the Host, filter PII, and configure GA4 forwarding.
Overview
The 1Shot Wallet Branding Layer (wallet.1shotapi.com) publishes product analytics events to your Host app over Postmate (ows:analytics). Your Host receives the full payload through proxy.analytics.on() after you create an OWSProxy — the same integration surface any customer uses.
At the wire layer this is vendor-agnostic: you choose whether to forward events to Google Analytics 4, Segment, PostHog, a first-party API, or all of the above. The sections below document a complete GA4 integration you can copy, including the PII-safe parameter policy used on www.1shotapi.com.
Subscribe in your Host app
Subscribe once after OWSProxy.create() succeeds. You do not need a separate handler per event name — every product event flows through the same listener. Call the returned unsubscribe function (or rely on proxy.destroy()) before tearing down the embed.
Minimal subscription
import { OWSProxy } from "@1shotapi/ows-provider";
const container = document.getElementById("wallet-container")!;
const proxy = await OWSProxy.create(container, "https://wallet.1shotapi.com/");
const unsubscribe = proxy.analytics.on((event) => {
console.info(event.name, event);
// Forward to your analytics vendor here
});
// On teardown:
unsubscribe();
proxy.destroy();Optional helper (mirrors 1Shot marketing site)
function subscribeWalletAnalytics(
proxy: OWSProxy,
onEvent: (event: IOWSAnalyticsEvent) => void,
): () => void {
return proxy.analytics.on(onEvent);
}
// After create:
const unsubscribe = subscribeWalletAnalytics(proxy, (event) => {
trackWalletAnalyticsEvent(event, "checkout"); // your surface label
});You can also narrow with proxy.analytics.on("PersonalSign", listener) when you only care about one name, but a single catch-all listener is enough for GA4.
Event catalog (27 names)
Each event includes base fields: eventId, timestamp, hostDomain, and name. The wallet attaches additional fields depending on the action (for example durationMs, chainId, errorCode). Narrow on event.name in your forwarder.
- Account —
AccountCreated,AccountCreateFailed,AccountCreateCancelled(accountAddress,errorCodeon failures) - EIP-191 (personal_sign) —
PersonalSign,PersonalSignFailed,PersonalSignCancelled(messageLength,durationMs,errorCode) - EIP-712 (typed data) —
TypedSign,TypedSignFailed,TypedSignCancelled(primaryType,durationMs,errorCode) - Send —
TransactionSubmitted,TransactionSubmitFailed,TransactionSubmitCancelled(chainId,to,txHash,methodId,durationMs,errorCode) - Credentials (OID4) —
CredentialIssued,CredentialIssueFailed,CredentialIssueCancelled,CredentialPresented,CredentialPresentFailed,CredentialPresentCancelled(issuerOrigin,verifierOrigin,durationMs,errorCode) - Delegations (EIP-7715) —
DelegationCreated,DelegationCreateFailed,DelegationCreateCancelled,DelegationCancelled,DelegationCancelFailed,DelegationCancelAborted(chainId,txHashon revoke success,durationMs,errorCode)
PII-safe forwarding
Wallet events can include on-chain identifiers. Third-party analytics (including GA4) should not receive values you could tie to a specific user or wallet.
Forward: host context you define (for example wallet_surface = checkout), host_domain from event.hostDomain, timing (duration_ms), chain (chain_id), failure codes (error_code), message metadata (message_length, primary_type, method_id), and credential party origins (issuer_origin, verifier_origin).
Do not forward: accountAddress, to, txHash.
GA4 event naming and parameters
Map each wallet event.name to a GA4 custom event: wallet_{snake_case(name)}. Example: PersonalSign → wallet_personal_sign, TransactionSubmitFailed → wallet_transaction_submit_failed. All 27 names fit GA4's 40-character event name limit.
Attach parameters using snake_case. At minimum send event_category: "wallet", wallet_event_name (original name), host_domain, and a host-defined wallet_surface (or equivalent) so you can segment embed locations in reports.
GA4 forwarder (reference implementation)
import type { IOWSAnalyticsEvent } from "@1shotapi/ows-types";
declare global {
interface Window {
gtag?: (...args: unknown[]) => void;
}
}
const WALLET_FIELD_TO_GA_PARAM: Record<string, string> = {
durationMs: "duration_ms",
chainId: "chain_id",
errorCode: "error_code",
messageLength: "message_length",
primaryType: "primary_type",
methodId: "method_id",
issuerOrigin: "issuer_origin",
verifierOrigin: "verifier_origin",
};
function walletEventToGaEventName(name: string): string {
return `wallet_${name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase()}`;
}
function trackWalletAnalyticsEvent(
event: IOWSAnalyticsEvent,
surface: string,
): void {
if (typeof window.gtag !== "function") return;
const params: Record<string, string | number | boolean> = {
event_category: "wallet",
wallet_surface: surface,
wallet_event_name: event.name,
host_domain: String(event.hostDomain),
};
for (const [key, gaKey] of Object.entries(WALLET_FIELD_TO_GA_PARAM)) {
const value = event[key];
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
params[gaKey] = value;
}
}
window.gtag("event", walletEventToGaEventName(event.name), params);
}The live marketing site implementation lives in app/lib/wallet-analytics.ts and uses wallet_surface values homepage, wallet_page, and playground.
Load GA4 in your app
Environment variable
NEXT_PUBLIC_GA4_MEASUREMENT_ID=G-XXXXXXXXXXLoad the gtag snippet once site-wide with your measurement ID (G-XXXXXXXXXX). Guard trackWalletAnalyticsEvent with typeof window.gtag === "function" so local dev without GA does not throw.
On the 1Shot marketing site, GA4 is loaded from app/components/Analytics.tsx via NEXT_PUBLIC_GA4_MEASUREMENT_ID (or an inline measurement ID in app/layout.tsx).
Configure Google Analytics 4
GA4 collects custom event names automatically — you do not pre-register each wallet_* event. Configure the portal so reports break out the parameters you care about.
Realtime updates in seconds; the main Events report can lag 24–48 hours. Custom dimensions apply to hits collected after registration.
- Verify hits — Open GA4 Admin → DebugView. Install the Google Analytics Debugger Chrome extension (or enable
debug_modetemporarily). Trigger wallet actions in your app and confirm events such aswallet_personal_signandwallet_account_createdappear withwallet_surfaceand other params. - Register custom dimensions — Admin → Data display → Custom definitions → Create custom dimension (scope: Event). Register at least:
wallet_surface,wallet_event_name,host_domain,chain_id,error_code,duration_ms. Parameter names must match what your forwarder sends. - Mark key events (optional) — Admin → Data display → Events. After events appear (often 24–48 hours in this list; DebugView is immediate), toggle Mark as key event for outcomes you track as conversions, for example
wallet_account_createdorwallet_transaction_submitted. - Build Explore reports — Use Explore → Free form or Funnel exploration. Filter event names to
wallet_*or break down by thewallet_surfacecustom dimension to compare embed locations.
Test before production
Use the wallet playground Analytics mode to inspect the live proxy.analytics stream (filter by name) while exercising connect, sign, send, credential, and delegation flows. The marketing playground also forwards the same events to GA4 using the reference forwarder above.