> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tappd.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Tappd Web SDK Examples: Patterns and Code Snippets

> Copy-ready Tappd Web SDK examples for e-commerce, auth, forms, React, Vue, Next.js, error tracking, A/B testing, and video analytics.

These examples show the Tappd Web SDK applied to real-world scenarios. Each section is self-contained — copy the code, swap in your own values, and drop it into your project. All examples assume you have already initialized the SDK with your `appId`.

***

<Accordion title="E-commerce">
  Track the full purchase funnel from product discovery through checkout, and capture cart abandonment for retargeting.

  **Product purchase flow:**

  ```javascript theme={null}
  import { TappdSDK } from '@tappd/web-sdk';

  const tappd = new TappdSDK({ appId: 'YOUR_APP_ID' });

  // 1. User views a product
  await tappd.track('ecommerce.product_viewed', {
    productId: 'prod_123',
    productName: 'iPhone 15',
    category: 'Electronics',
    price: 999.00,
    currency: 'USD'
  });

  // 2. User adds the product to their cart
  await tappd.track('ecommerce.add_to_cart', {
    productId: 'prod_123',
    productName: 'iPhone 15',
    quantity: 1,
    price: 999.00,
    currency: 'USD'
  });

  // 3. User begins checkout
  await tappd.track('ecommerce.checkout_started', {
    cartValue: 999.00,
    currency: 'USD'
  });

  // 4. User completes the purchase
  await tappd.track('ecommerce.purchase', {
    orderId: 'ord_456',
    total: 999.00,
    currency: 'USD',
    items: [
      {
        productId: 'prod_123',
        name: 'iPhone 15',
        price: 999.00,
        quantity: 1
      }
    ]
  });
  ```

  **Cart abandonment tracking:**

  ```javascript theme={null}
  async function trackCartAbandonment(cartItems) {
    await tappd.track('ecommerce.cart_abandoned', {
      cartValue: calculateTotal(cartItems),
      itemCount: cartItems.length,
      items: cartItems,
      currency: 'USD'
    });
  }
  ```
</Accordion>

<Accordion title="User Authentication">
  Capture the complete sign-up and login lifecycle — including failures — so you can analyze drop-off and optimize your onboarding funnel.

  **Sign-up flow:**

  ```javascript theme={null}
  async function handleSignUp(email, name) {
    // Track the attempt before any async work
    await tappd.track('user.signup.started', { method: 'email' });

    try {
      const user = await createAccount(email, name);

      // Identify the user — this merges all pre-signup anonymous events
      await tappd.identify({
        external_id: user.id,
        email: email,
        name: name,
        signupDate: new Date().toISOString()
      });

      // No userId needed — SDK auto-links to the identified user
      await tappd.track('user.signup.completed', { method: 'email' });
    } catch (error) {
      await tappd.track('user.signup.failed', {
        method: 'email',
        error: error.message
      });
    }
  }
  ```

  **Login flow:**

  ```javascript theme={null}
  async function handleLogin(email) {
    await tappd.track('user.login.started', { method: 'email' });

    try {
      const user = await authenticate(email);

      await tappd.identify({
        external_id: user.id,
        email: user.email,
        name: user.name,
        lastLogin: new Date().toISOString()
      });

      await tappd.track('user.login.completed', { method: 'email' });
    } catch (error) {
      await tappd.track('user.login.failed', {
        method: 'email',
        error: error.message
      });
    }
  }
  ```

  **Logout:**

  ```javascript theme={null}
  function handleLogout() {
    // Track the logout event before resetting
    tappd.track('user.logout');

    // Clear user identity — next events will be anonymous
    tappd.reset();
  }
  ```
</Accordion>

<Accordion title="Form Tracking">
  Instrument multi-step forms to understand where users engage, hesitate, or drop off.

  ```javascript theme={null}
  // Step 1 — User lands on the form
  await tappd.track('form.viewed', {
    formId: 'checkout-form',
    formName: 'Checkout'
  });

  // Step 2 — User starts filling in fields
  await tappd.track('form.started', {
    formId: 'checkout-form',
    formName: 'Checkout'
  });

  // Step 3 — User completes an individual step
  await tappd.track('form.step_completed', {
    formId: 'checkout-form',
    formName: 'Checkout',
    step: 'shipping',
    stepNumber: 1
  });

  // Step 4 — User submits the form
  await tappd.track('form.submitted', {
    formId: 'checkout-form',
    formName: 'Checkout',
    success: true,
    fieldsCompleted: 5
  });
  ```
</Accordion>

<Accordion title="Subscription Management">
  Track plan changes and update user attributes in a single flow so your customer profiles stay current.

  **Plan upgrade:**

  ```javascript theme={null}
  async function handleUpgrade(newPlan, userId) {
    const currentPlan = getUserPlan();

    await tappd.track('subscription.upgrade', {
      fromPlan: currentPlan,
      toPlan: newPlan,
      upgradeDate: new Date().toISOString()
    });

    // Sync the new plan to the user's Tappd profile
    // external_id must match the value used in identify()
    await tappd.setUserAttributes({
      external_id: userId,
      plan: newPlan,
      upgradedAt: new Date().toISOString()
    });
  }
  ```

  **Subscription cancellation:**

  ```javascript theme={null}
  async function handleCancellation(reason, userId) {
    await tappd.track('subscription.cancelled', {
      reason: reason,
      cancelledAt: new Date().toISOString()
    });

    await tappd.setUserAttributes({
      external_id: userId,
      planStatus: 'cancelled',
      cancellationDate: new Date().toISOString()
    });
  }
  ```
</Accordion>

<Accordion title="React Integration">
  Use a lightweight hook for simple components, or set up a Context provider to share the SDK instance across your entire app.

  **`useTappd` hook:**

  ```javascript theme={null}
  import { useEffect, useState } from 'react';
  import { TappdSDK } from '@tappd/web-sdk';

  function useTappd() {
    const [tappd] = useState(() => {
      return new TappdSDK({
        appId: process.env.REACT_APP_TAPPD_APP_ID
      });
    });

    return tappd;
  }

  // Usage inside a component
  function ProductPage({ productId }) {
    const tappd = useTappd();

    useEffect(() => {
      tappd.track('product_viewed', { productId });
    }, [productId]);

    const handleAddToCart = async () => {
      await tappd.track('add_to_cart', { productId });
    };

    return <button onClick={handleAddToCart}>Add to Cart</button>;
  }
  ```

  **React Context provider/consumer:**

  ```javascript theme={null}
  import React, { createContext, useContext } from 'react';
  import { TappdSDK } from '@tappd/web-sdk';

  const TappdContext = createContext(null);

  // Wrap your app root with this provider
  export function TappdProvider({ children }) {
    const tappd = new TappdSDK({
      appId: process.env.REACT_APP_TAPPD_APP_ID
    });

    return (
      <TappdContext.Provider value={tappd}>
        {children}
      </TappdContext.Provider>
    );
  }

  // Consume the shared instance anywhere in the tree
  export function useTappd() {
    return useContext(TappdContext);
  }
  ```
</Accordion>

<Accordion title="Vue.js Integration">
  Create a composable that initializes the SDK on mount and exposes it reactively throughout your Vue app.

  ```javascript theme={null}
  // composables/useTappd.js
  import { ref, onMounted } from 'vue';
  import { TappdSDK } from '@tappd/web-sdk';

  export function useTappd() {
    const tappd = ref(null);

    onMounted(() => {
      tappd.value = new TappdSDK({
        appId: import.meta.env.VITE_TAPPD_APP_ID
      });
    });

    return tappd;
  }
  ```

  ```vue theme={null}
  <!-- Usage inside a component -->
  <script setup>
  import { useTappd } from '@/composables/useTappd';

  const tappd = useTappd();

  const handleClick = async () => {
    await tappd.value?.track('button_click', { buttonId: 'cta' });
  };
  </script>

  <template>
    <button @click="handleClick">Get Started</button>
  </template>
  ```
</Accordion>

<Accordion title="Next.js App Router">
  Initialize the SDK in your root layout using `useEffect` and clean up with `reset()` when the component unmounts.

  ```typescript theme={null}
  // app/layout.tsx
  'use client';

  import { useEffect } from 'react';
  import { TappdSDK } from '@tappd/web-sdk';

  export default function RootLayout({
    children
  }: {
    children: React.ReactNode
  }) {
    useEffect(() => {
      const tappd = new TappdSDK({
        appId: process.env.NEXT_PUBLIC_TAPPD_APP_ID as string
      });

      // Make the instance globally available if needed
      (window as any).tappd = tappd;

      // Clean up on unmount
      return () => {
        tappd.reset();
      };
    }, []);

    return (
      <html lang="en">
        <body>{children}</body>
      </html>
    );
  }
  ```
</Accordion>

<Accordion title="Next.js Pages Router">
  For the Pages Router, initialize the SDK inside `_app.js` so the instance is created once and shared across all pages.

  ```javascript theme={null}
  // pages/_app.js
  import { useEffect } from 'react';
  import { TappdSDK } from '@tappd/web-sdk';

  function MyApp({ Component, pageProps }) {
    useEffect(() => {
      const tappd = new TappdSDK({
        appId: process.env.NEXT_PUBLIC_TAPPD_APP_ID
      });

      // Make the instance globally available if needed
      window.tappd = tappd;
    }, []);

    return <Component {...pageProps} />;
  }

  export default MyApp;
  ```
</Accordion>

<Accordion title="Error Tracking">
  Capture unhandled JavaScript errors and promise rejections to monitor application health alongside your user behavior data.

  ```javascript theme={null}
  // Capture synchronous runtime errors
  window.addEventListener('error', (event) => {
    tappd.track('error', {
      message: event.message,
      filename: event.filename,
      lineno: event.lineno,
      colno: event.colno,
      stack: event.error?.stack
    });
  });

  // Capture unhandled promise rejections
  window.addEventListener('unhandledrejection', (event) => {
    tappd.track('error.unhandled_promise_rejection', {
      reason: String(event.reason),
      stack: event.reason?.stack
    });
  });
  ```
</Accordion>

<Accordion title="A/B Testing">
  Track experiment exposure and conversions to measure the impact of each variant directly within Tappd.

  ```javascript theme={null}
  // Assign and record the variant at experiment entry
  const variant = getExperimentVariant('homepage-cta');

  await tappd.track('experiment.viewed', {
    experimentId: 'homepage-cta',
    variant: variant
    // No userId needed — SDK auto-associates with the identified user
  });

  // Record a conversion later in the user flow
  await tappd.track('experiment.converted', {
    experimentId: 'homepage-cta',
    variant: variant,
    conversionType: 'signup'
  });
  ```
</Accordion>

<Accordion title="Video Tracking">
  Instrument native HTML5 `<video>` elements to measure play rate, pause behavior, and completion rate.

  ```javascript theme={null}
  const video = document.querySelector('video');

  video.addEventListener('play', () => {
    tappd.track('video.played', {
      videoId: 'intro-video',
      videoTitle: 'Product Introduction'
    });
  });

  video.addEventListener('pause', () => {
    tappd.track('video.paused', {
      videoId: 'intro-video',
      currentTime: video.currentTime,
      duration: video.duration,
      percentWatched: Math.round((video.currentTime / video.duration) * 100)
    });
  });

  video.addEventListener('ended', () => {
    tappd.track('video.completed', {
      videoId: 'intro-video',
      duration: video.duration
    });
  });
  ```
</Accordion>
