Skip to main content

Quickstart

This guide takes you from zero to a working iframe inside your app. It assumes you already have a CoinTracker partner agreement and credentials to mint JWTs — if not, reach out to your CoinTracker integration owner to kick that off. See Integration planning for what to bring to kickoff.

Before you start

You'll need:

  • An active CoinTracker partner integration — your slug enrolled, credentials issued. See Integration planning.
  • JWT-minting credentials from your CoinTracker integration owner — these go on your backend, never in the browser.
  • A React 16.8+, 17, 18, or 19 frontend with the part of your app where the kit should live identified.
  • A backend endpoint you control that can exchange your partner credentials for a CoinTracker JWT.
  • Browser-policy headers compatible with the iframe on the page that renders the kit:
    • CSP — your frame-src directive must allow https://embedded.cointracker.com (or the staging origin if you're using it). If you don't set a CSP at all, you're already fine.
    • Permissions-Policy — the iframe requests clipboard-write (for copy-to-clipboard) and payment (for the subscription/upgrade flow). The SDK sets the iframe's allow attribute automatically — you only need to take action if your parent page sets a strict Permissions-Policy that blocks these features from being delegated to iframes.

Browser support: the kit targets evergreen Chromium, Firefox, Safari, and their mobile equivalents. iOS Safari 15+ and Android Chrome 100+ are the practical floors.

  1. 1

    Install the package

    npm install @cointracker/tax-kit
    # or
    bun add @cointracker/tax-kit

    Supported React versions: 16.8+, 17, 18, 19.

  2. 2

    Implement the token handler on your backend

    Your backend exchanges your partner credentials with CoinTracker for a short-lived JWT and returns it to your frontend. The exact shape of the request to CoinTracker is partner-specific — your CoinTracker integration contact will provide the endpoint and required claims.

    // Example partner backend handler (Express-style pseudocode)
    app.post('/api/cointracker-token', async (req, res) => {
    const token = await mintCointrackerJwt({
    partnerUserId: req.session.userId,
    // …additional claims required by your CoinTracker integration
    });
    res.json({ access_token: token });
    });
    warning

    Never expose your partner credentials to the browser. The JWT must be minted server-side and returned to the frontend over an authenticated channel.

  3. 3

    Mount TaxKitProvider above the tax page

    Mount TaxKitProvider above the route or component subtree that needs the kit — typically your tax-center page. The iframe is positioned fixed and covers the viewport when opened, so it doesn't matter where exactly in the DOM the provider sits — only that it's a React ancestor of any component calling useTaxKit().

    import { TaxKitProvider } from '@cointracker/tax-kit';

    export default function TaxCenterPage() {
    const fetchAccessToken = async () => {
    const res = await fetch('/api/cointracker-token', { method: 'POST' });
    const { access_token } = await res.json();
    return access_token;
    };

    return (
    <TaxKitProvider fetchAccessToken={fetchAccessToken}>
    <YourTaxCenterContent />
    </TaxKitProvider>
    );
    }

    fetchAccessToken is the only required prop. The provider calls it whenever the iframe needs to authenticate — including when the existing token is within 30 seconds of expiry.

    Where to mount it: scope the provider as narrowly as the kit actually needs to be reachable. Wrapping it around your tax-center route is the common case. Wrapping the entire root app works but mounts the iframe (and the post-robot bridge) on every page — wasted work on pages that don't use the kit.

  4. 4

    Open the kit from a button

    import { useTaxKit } from '@cointracker/tax-kit';

    function TaxCenter() {
    const { open, numberOfConnections, taxKitStatus } = useTaxKit();
    return (
    <button onClick={open}>
    {numberOfConnections != null
    ? `Open Tax Kit (${numberOfConnections} connection${numberOfConnections === 1 ? '' : 's'})`
    : 'Get started'}
    </button>
    );
    }

Where to go next

tip

For a dedicated tax page where users land directly on the kit, pass options.defaultOpen: true so the iframe renders open on first paint. This avoids password-manager "Save password?" prompts triggered by click-then-form-appeared.