Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.cryptique.io/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This guide covers implementation patterns for common Web3 analytics scenarios. Use these patterns to ensure comprehensive, accurate tracking.

Implementation Workflow

1

Plan Your Events

Define what you want to measure before writing code
2

Install SDK

Add Cryptique to your application
3

Configure Auto-Events

Enable/disable automatic tracking
4

Add Custom Events

Track business-specific actions
5

Set Up Identification

Link users across sessions
6

Integrate Wallets

Connect wallet events to user profiles
7

Verify & Iterate

Test tracking and refine

Common Patterns

Authentication Flow

Track the complete auth journey:
// Signup started
Cryptique.track('signup_started', {
  signup_method: 'email',  // or 'google', 'wallet'
  referral_source: getReferralSource()
});

// Signup completed
Cryptique.track('signup_completed', {
  signup_method: 'email',
  time_to_complete_seconds: 45
});

// Identify the user
Cryptique.identify(user.id);

// Set user properties
Cryptique.people.set({
  email: user.email,
  name: user.name,
  signup_date: new Date().toISOString(),
  signup_method: 'email'
});

// Set persistent properties
Cryptique.people.set_once({
  first_seen: new Date().toISOString(),
  original_referrer: document.referrer
});

Wallet Connection Flow

Track wallet interactions:
// Wallet connection initiated
Cryptique.track('wallet_connect_initiated', {
  wallet_type: 'metamask',
  trigger_location: 'navbar'  // or 'modal', 'onboarding'
});

// Wallet connected successfully
async function onWalletConnected(address, provider) {
  // Track with SDK
  Cryptique.walletAddress(address);
  Cryptique.track('wallet_connected', {
    wallet_type: getWalletType(provider),
    chain_id: await provider.getChainId()
  });
  
  // Optional: set user properties
  Cryptique.people.set({
    primary_wallet: address,
    last_wallet_connect: new Date().toISOString()
  });
  
  Cryptique.people.increment({
    wallet_connect_count: 1
  });
}

// Wallet connection failed
function onWalletError(error) {
  Cryptique.track('wallet_connect_failed', {
    error_type: error.code,
    error_message: error.message,
    wallet_type: 'metamask'
  });
}

// Wallet disconnected
function onWalletDisconnected(address) {
  Cryptique.track('wallet_disconnected', { address });
}

// Chain changed
function onChainChanged(chainId, address) {
  Cryptique.track('chain_changed', {
    new_chain_id: chainId,
    wallet_address: address
  });
}

DeFi Swap Flow

Track the complete swap journey:
// Token selected
Cryptique.track('token_selected', {
  token_symbol: 'ETH',
  token_address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
  selection_type: 'input',  // or 'output'
  search_query: searchTerm || null
});

// Swap quoted
Cryptique.track('swap_quoted', {
  input_token: 'ETH',
  output_token: 'USDC',
  input_amount: 1.5,
  output_amount: 1485.50,
  exchange_rate: 990.33,
  slippage_setting: 0.5,
  route_provider: 'uniswap'
});

// Swap initiated (user clicked swap)
Cryptique.track('swap_initiated', {
  input_token: 'ETH',
  output_token: 'USDC',
  input_amount: 1.5,
  output_amount_expected: 1485.50,
  slippage_setting: 0.5
});

// Transaction approval requested
Cryptique.track('transaction_approval_requested', {
  token: 'USDC',
  spender: '0x...router',
  amount: 'unlimited'  // or specific amount
});

// Swap completed (after on-chain confirmation)
Cryptique.track('swap_completed', {
  input_token: 'ETH',
  output_token: 'USDC',
  input_amount: 1.5,
  output_amount_actual: 1483.20,
  slippage_actual: 0.15,
  transaction_hash: txHash,
  gas_used: gasUsed,
  gas_price_gwei: gasPriceGwei
});

// Swap failed
Cryptique.track('swap_failed', {
  input_token: 'ETH',
  output_token: 'USDC',
  input_amount: 1.5,
  error_type: 'slippage_exceeded',  // or 'user_rejected', 'insufficient_gas'
  error_message: error.message
});

NFT Mint Flow

// Collection viewed
Cryptique.track('collection_viewed', {
  collection_name: 'Cool Cats',
  collection_address: '0x...',
  items_available: 500,
  price_eth: 0.05
});

// Mint initiated
Cryptique.track('mint_initiated', {
  collection_name: 'Cool Cats',
  quantity: 2,
  total_price_eth: 0.10,
  mint_type: 'public'  // or 'whitelist', 'allowlist'
});

// Mint completed
Cryptique.track('mint_completed', {
  collection_name: 'Cool Cats',
  quantity: 2,
  token_ids: [1234, 1235],
  total_price_eth: 0.10,
  transaction_hash: txHash
});

Onboarding Flow

Track multi-step onboarding:
const ONBOARDING_STEPS = [
  'welcome',
  'connect_wallet',
  'verify_email',
  'set_preferences',
  'first_action'
];

function trackOnboardingStep(step, additionalProps = {}) {
  const stepIndex = ONBOARDING_STEPS.indexOf(step);
  
  Cryptique.track('onboarding_step_completed', {
    step_name: step,
    step_number: stepIndex + 1,
    total_steps: ONBOARDING_STEPS.length,
    ...additionalProps
  });
  
  // Update user property
  Cryptique.people.set({
    onboarding_step: step,
    onboarding_progress: Math.round((stepIndex + 1) / ONBOARDING_STEPS.length * 100)
  });
}

// On completion
function completeOnboarding() {
  Cryptique.track('onboarding_completed', {
    total_time_seconds: timeSinceStart,
    steps_completed: completedSteps.length,
    skipped_steps: skippedSteps
  });
  
  Cryptique.people.set({
    onboarding_completed: true,
    onboarding_completed_date: new Date().toISOString()
  });
}

Error Tracking

Track errors for debugging:
// Generic error tracking
function trackError(error, context) {
  Cryptique.track('error_occurred', {
    error_type: error.name,
    error_message: error.message,
    error_code: error.code,
    context: context,
    page: window.location.pathname
  });
}

// Transaction error
function trackTransactionError(error, txDetails) {
  Cryptique.track('transaction_error', {
    error_type: classifyError(error),
    error_message: error.message,
    transaction_type: txDetails.type,
    chain_id: txDetails.chainId,
    gas_estimate: txDetails.gasEstimate
  });
}

// Classify errors for better analysis
function classifyError(error) {
  if (error.code === 4001) return 'user_rejected';
  if (error.code === -32603) return 'internal_error';
  if (error.message.includes('insufficient funds')) return 'insufficient_funds';
  if (error.message.includes('gas')) return 'gas_error';
  return 'unknown';
}

Framework-Specific Patterns

React with Wagmi

import { useAccount, useConnect, useDisconnect } from 'wagmi';
import { useEffect } from 'react';

function WalletTracker() {
  const { address, isConnected, chain } = useAccount();
  const { connect, connectors } = useConnect();
  const { disconnect } = useDisconnect();
  
  // Track connection state changes
  useEffect(() => {
    if (isConnected && address) {
      Cryptique.walletAddress(address);
      Cryptique.track('wallet_connected', {
        chain_id: chain?.id,
        wallet_type: connectors[0]?.name || 'unknown'
      });
    }
  }, [isConnected, address, chain]);
  
  // Track disconnection
  const handleDisconnect = () => {
    if (address) {
      Cryptique.track('wallet_disconnected', { address });
    }
    disconnect();
  };
  
  return (/* ... */);
}

Next.js App Router

// app/providers.jsx
'use client';

import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
import Cryptique from 'cryptique-sdk';

export function AnalyticsProvider({ children }) {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  
  // Track page views on route change
  useEffect(() => {
    // Auto page_view should handle this, but for SPAs:
    Cryptique.track('page_view', {
      page_path: pathname,
      query_string: searchParams.toString()
    });
  }, [pathname, searchParams]);
  
  return children;
}

Vue 3 Composition API

// composables/useTracking.js
import { watch } from 'vue';
import { useRoute } from 'vue-router';
import Cryptique from 'cryptique-sdk';

export function useTracking() {
  const route = useRoute();
  
  // Track route changes
  watch(
    () => route.fullPath,
    (newPath) => {
      Cryptique.track('page_view', {
        page_path: newPath
      });
    }
  );
  
  const trackEvent = (name, properties) => {
    Cryptique.track(name, properties);
  };
  
  return { trackEvent };
}

Groups (companies, teams, workspaces)

Model B2B or multi-tenant context with Groups: assign the user, then set properties on the group profile.
Cryptique.identify(user.id);

await Cryptique.set_group('company', user.companyId);

const company = Cryptique.get_group('company', user.companyId);
await company.set({
  name: user.companyName,
  plan: user.companyPlan
});

Cryptique.track('report_exported', { format: 'csv' });
Use add_group / remove_group when a user can belong to multiple IDs under the same key. After identify(), the server may return group_memberships to hydrate assignments on a new device.

Testing Your Implementation

Debug Mode

Enable debug logging:
// CDN
script.setAttribute('debug', 'true');

// npm
await Cryptique.init({
  siteId: 'YOUR_SITE_ID',
  debug: true  // Logs all events to console
});

Verification Checklist

1

Check Live Events

Go to Dashboard → Live Events and perform actions
2

Verify User Profiles

Check that identify() creates/updates profiles
3

Test Wallet Linking

Connect wallet and verify it appears on profile
4

Check Properties

Verify all expected properties are present
5

Test Error Cases

Trigger errors and verify tracking

Common Issues

  • Check Site ID is correct
  • Verify domain is allowed in settings
  • Check for ad blocker interference
  • Look for console errors
  • Ensure identify() is called after SDK loads
  • Verify distinct_id is a string
  • Check that properties are valid JSON
  • Call Cryptique.walletAddress() with a valid address
  • Verify address format (0x…)
  • Confirm the SDK session initialized (Site ID, domain allowlist)
  • Check SDK isn’t initialized twice
  • Verify event handlers aren’t double-bound
  • Review SPA routing configuration

Next Steps

SDK Reference

Full method documentation

Build Reports

Analyze your data