Skip to main content

Vanilla JavaScript / Standalone SDK

Use the TagadaPay SDK in any JavaScript project - no framework required!
Perfect for:
  • Pure HTML/CSS/JS sites
  • Server-rendered apps
  • Other frameworks (Svelte, Angular, Vue, etc.)
  • WordPress, Shopify, or any platform

Quick Start

Installation

npm install @tagadapay/plugin-sdk

Basic Usage

import { createTagadaClient, FunnelActionType } from '@tagadapay/plugin-sdk/v2/standalone';

// 1. Create client - funnel auto-initializes!
const client = createTagadaClient({
  features: { funnel: true }
});

// 2. Subscribe to funnel state
client.funnel.subscribe((funnelState) => {
  if (funnelState.isInitialized && funnelState.context) {
    console.log('✅ Funnel ready!', funnelState.context);
    // Render your UI here
  }
});

// 3. Use funnel methods
document.getElementById('pay-btn').onclick = async () => {
  await client.funnel.navigate({
    type: FunnelActionType.PAYMENT_SUCCESS,
    data: {
      order: { id: 'ord_123', amount: 99.99 }
    }
  });
  // Auto-redirects to next page!
};
That’s it! No manual initialization, no complex state management. The SDK handles everything automatically.

How It Works

The SDK automatically:
  1. ✅ Creates an anonymous session
  2. ✅ Initializes the funnel (when enabled)
  3. ✅ Loads configuration and static resources
  4. ✅ Handles navigation and redirects
All you do is:
  1. Create the client
  2. Subscribe to get updates
  3. Use client.funnel.navigate() to move between steps

Complete Example

Here’s a full checkout page in vanilla JavaScript:
import { createTagadaClient, FunnelActionType } from '@tagadapay/plugin-sdk/v2/standalone';

// Create client
const client = createTagadaClient({
  features: { funnel: true }
});

// Subscribe to funnel ready state
client.funnel.subscribe((funnelState) => {
  if (funnelState.isInitialized && funnelState.context) {
    renderCheckout(funnelState.context);
  } else if (funnelState.error) {
    showError(funnelState.error.message);
  }
});

function renderCheckout(context) {
  // Get static resources (configured in CRM)
  const offerId = context.static?.offer?.id;
  
  // Get context data (from previous steps)
  const order = context.resources?.order;
  const customer = context.resources?.customer;
  
  // Render your UI
  document.getElementById('customer-email').textContent = customer?.email || 'Guest';
  document.getElementById('order-total').textContent = `$${order?.amount || 0}`;
  
  // Setup payment button
  document.getElementById('pay-btn').onclick = async () => {
    try {
      await client.funnel.navigate({
        type: FunnelActionType.PAYMENT_SUCCESS,
        data: {
          resources: {
            order: {
              id: 'ord_123',
              amount: 4900,
              currency: 'USD'
            },
            customer: {
              email: document.getElementById('email-input').value
            }
          }
        }
      });
      // Automatically redirects to thank you page!
    } catch (error) {
      alert('Payment failed: ' + error.message);
    }
  };
}

function showError(message) {
  document.getElementById('error').textContent = message;
}

Available Methods

Client State

// Get current state
const state = client.getState();
console.log(state.store);     // Store info
console.log(state.customer);  // Customer info
console.log(state.session);   // Session info

// Subscribe to state changes
client.subscribe((state) => {
  console.log('State updated:', state);
});

Funnel Methods

// Navigate to next step
await client.funnel.navigate({
  type: FunnelActionType.PAYMENT_SUCCESS,
  data: { /* your data */ }
});

// Update funnel context
await client.funnel.updateContext({
  metadata: {
    customField: 'value'
  }
});

// Get current funnel state
const funnelState = client.funnel.getState();
console.log(funnelState.context);      // Current funnel context
console.log(funnelState.isLoading);    // Loading state
console.log(funnelState.error);        // Error if any

Funnel Action Types

All available action types for funnel.navigate():
FunnelActionType.PAYMENT_SUCCESS     // Payment completed
FunnelActionType.PAYMENT_FAILED      // Payment failed
FunnelActionType.OFFER_ACCEPTED      // Upsell accepted
FunnelActionType.OFFER_DECLINED      // Upsell declined
FunnelActionType.FORM_SUBMITTED      // Form completed
FunnelActionType.SKIP                // Skip current step

Working with Static Resources

Static resources are configured by merchants in the CRM. Your code accesses them dynamically:
client.funnel.subscribe((funnelState) => {
  if (funnelState.context) {
    // Access static resources
    const offerId = funnelState.context.static?.offer?.id;
    const productId = funnelState.context.static?.product?.id;
    const variantId = funnelState.context.static?.variant?.id;
    
    // Fetch the actual offer data
    if (offerId) {
      fetchOffer(offerId).then(offer => {
        document.getElementById('offer-title').textContent = offer.title;
        document.getElementById('offer-price').textContent = `$${offer.price}`;
      });
    }
  }
});

Local Testing

For local development, create config/resources.static.json:
{
  "offer": {
    "id": "offer_test123"
  },
  "product": {
    "id": "prod_test456"
  }
}
The SDK automatically loads this in local dev!

Configuration

const client = createTagadaClient({
  // Environment (auto-detected by default)
  environment: 'production',  // 'local' | 'development' | 'production'
  
  // Debug mode (auto-enabled in local dev)
  debugMode: true,
  
  // Features
  features: {
    funnel: true,  // Enable funnel navigation
  },
  
  // Local config name (for testing different presets)
  localConfig: 'premium',  // Loads config/premium.config.json
});

Error Handling

// Funnel errors
client.funnel.subscribe((funnelState) => {
  if (funnelState.error) {
    console.error('Funnel error:', funnelState.error);
    showErrorMessage(funnelState.error.message);
  }
  
  if (funnelState.sessionError) {
    console.error('Session error:', funnelState.sessionError);
    // Session initialization failed
  }
});

// Navigation errors
try {
  await client.funnel.navigate({
    type: FunnelActionType.PAYMENT_SUCCESS,
    data: { /* ... */ }
  });
} catch (error) {
  console.error('Navigation failed:', error);
  alert('Failed to proceed: ' + error.message);
}

TypeScript Support

Full TypeScript support included:
import { 
  createTagadaClient, 
  FunnelActionType,
  type TagadaState,
  type SimpleFunnelContext 
} from '@tagadapay/plugin-sdk/v2/standalone';

const client = createTagadaClient({
  features: { funnel: true }
});

client.subscribe((state: TagadaState) => {
  // Fully typed!
  console.log(state.store?.id);
  console.log(state.customer?.email);
});

client.funnel.subscribe((funnelState) => {
  if (funnelState.context) {
    const context: SimpleFunnelContext = funnelState.context;
    // All context properties are typed
  }
});

Real-World Example: Checkout Page

<!DOCTYPE html>
<html>
<head>
  <title>Checkout</title>
</head>
<body>
  <div id="app">
    <div id="loading">Loading...</div>
    <div id="checkout" style="display: none;">
      <h1>Checkout</h1>
      <div id="order-summary"></div>
      <input id="email" type="email" placeholder="Email" />
      <button id="pay-btn">Pay Now</button>
    </div>
    <div id="error"></div>
  </div>
  
  <script type="module" src="/main.js"></script>
</body>
</html>
// main.js
import { createTagadaClient, FunnelActionType } from '@tagadapay/plugin-sdk/v2/standalone';

const client = createTagadaClient({
  features: { funnel: true }
});

let globalOrder = null;

// Wait for funnel ready
client.funnel.subscribe((funnelState) => {
  if (funnelState.isInitialized && funnelState.context) {
    document.getElementById('loading').style.display = 'none';
    document.getElementById('checkout').style.display = 'block';
    
    // Get order from context (if coming from previous step)
    globalOrder = funnelState.context.resources?.order || {
      id: 'new-order',
      amount: 4900,
      currency: 'USD'
    };
    
    document.getElementById('order-summary').innerHTML = `
      <p>Total: $${(globalOrder.amount / 100).toFixed(2)}</p>
    `;
  } else if (funnelState.error) {
    document.getElementById('loading').style.display = 'none';
    document.getElementById('error').textContent = funnelState.error.message;
  }
});

// Handle payment
document.getElementById('pay-btn').onclick = async () => {
  const email = document.getElementById('email').value;
  
  if (!email) {
    alert('Please enter your email');
    return;
  }
  
  try {
    await client.funnel.navigate({
      type: FunnelActionType.PAYMENT_SUCCESS,
      data: {
        resources: {
          order: {
            ...globalOrder,
            status: 'paid'
          },
          customer: {
            email,
            id: `cus_${Date.now()}`
          }
        }
      }
    });
    // Auto-redirects to next page (upsell or thank you)
  } catch (error) {
    alert('Payment failed: ' + error.message);
  }
};

Comparison: Before vs After

❌ Old Way (Too Complex)

const client = createTagadaClient({ features: { funnel: true } });

// Wait for client ready
client.subscribe(async (state) => {
  if (state.isInitialized && state.auth.session && state.store) {
    // Manual funnel initialization
    const context = await client.funnel.autoInitialize(
      { customerId: state.auth.session.customerId },
      { id: state.store.id, accountId: state.store.accountId }
    );
    
    // Now render UI...
  }
});

✅ New Way (Simple!)

const client = createTagadaClient({ features: { funnel: true } });

// Funnel auto-initializes - just subscribe!
client.funnel.subscribe((funnelState) => {
  if (funnelState.isInitialized && funnelState.context) {
    // Render UI immediately
  }
});

Next Steps

Build a Funnel

Follow the step-by-step tutorial

Funnel Resources

Learn about passing data between steps

API Reference

Explore all available methods

Examples

See complete examples