Trackdolphin

Schnellstart SvelteKit

Für Headless-Shops gibt es kein Plugin — dafür das SDK. Der Weg ist derselbe wie bei den Plugins: Der Browser spricht nur mit deiner Domain, dein Server spricht mit dem Collector. Warum das wichtig ist, steht unter 100 % Abdeckung; hier geht es um die Umsetzung.

bash
npm install @trackdolphin/sdk

Du brauchst die Collector-URL aus dem Dashboard unter Einrichtung. Sie steht in deinem Server-Environment, nicht im Browser — über $env/static/private bricht der Build, wenn sie fehlt, statt dass der Shop still nichts sendet:

bash
# .env
TD_ENDPOINT=https://abc123.trdph.com/collect

1. Die Proxy-Route

Eine Datei. Sie nimmt Events vom Browser an, ergänzt Besucher-IP und User-Agent, setzt die Besucherkennung als echtes Server-Cookie und reicht alles an den Collector weiter. Fehler landen im Server-Log, nie im Browser.

ts
// src/routes/td/+server.ts
import { TD_ENDPOINT } from "$env/static/private";
import { createCollectProxy } from "@trackdolphin/sdk/proxy";
import type { RequestHandler } from "./$types";

const proxy = createCollectProxy({ endpoint: TD_ENDPOINT });

export const POST: RequestHandler = ({ request }) => proxy(request);
export const OPTIONS = POST;

2. SDK starten und Seitenaufrufe melden

init() gehört ins Root-Layout, und weil SvelteKit zwischen Routen keine neue Seite lädt, kommen Seitenaufrufe aus afterNavigate — das läuft auch beim ersten Rendern.

svelte
<!-- src/routes/+layout.svelte -->
<script lang="ts">
  import { afterNavigate } from "$app/navigation";
  import { init, track } from "@trackdolphin/sdk";

  let { children } = $props();

  // Relativ: der Browser sieht nur deine Domain. Die Besucherkennung
  // vergibt die Route (Set-Cookie) — das SDK liest sie nur.
  init({ endpoint: "/td", requireConsent: true });

  afterNavigate(() => {
    track({ type: "custom", custom_name: "page_view" });
  });
</script>

{@render children()}

Die Einwilligung aus deinem Cookie-Banner übergibst du mit setConsent() — als true/false oder granular nach Consent Mode v2. Mit requireConsent: true bleiben Events bis dahin in der Warteschlange.

3. Produkt und Warenkorb

svelte
<!-- src/routes/produkt/[slug]/+page.svelte -->
<script lang="ts">
  import { viewItem, addToCart } from "@trackdolphin/sdk";

  let { data } = $props();
  const item = { id: data.product.sku, name: data.product.name, price: data.product.price };

  // Beim Laden der Seite (und bei jedem Produktwechsel)
  $effect(() => {
    viewItem([item], item.price);
  });
</script>

<button onclick={() => addToCart([item], item.price)}>In den Warenkorb</button>

4. Der Kauf: Browser und Server mit derselben event_id

Der verlässliche Kauf kommt vom Server — aus der Bestellung, nicht aus dem Browser. Damit Meta beide Seiten als eine Conversion erkennt, teilen sich Browser und Server die event_id. Ableiten, nicht würfeln: order_${id}.

Serverseitig in der Form-Action, die die Bestellung abschließt:

ts
// src/routes/checkout/+page.server.ts
import { TD_ENDPOINT } from "$env/static/private";
import { createClient } from "@trackdolphin/sdk/server";
import { redirect } from "@sveltejs/kit";
import type { Actions } from "./$types";

const td = createClient({ endpoint: TD_ENDPOINT });

export const actions: Actions = {
  default: async ({ request }) => {
    const form = await request.formData();
    const order = await finishOrder(form);   // zuerst das Geschäft

    try {
      await td.purchase({
        event_id: `order_${order.id}`,
        value: order.total,
        currency: "EUR",
        email: order.email,        // wird hier gehasht, verlässt den Server nie im Klartext
        phone: order.phone,
        items: order.items.map((i) => ({ id: i.sku, quantity: i.quantity, price: i.price })),
      });
    } catch (e) {
      console.error("Tracking fehlgeschlagen — Bestellung ist gesichert", e);
    }

    redirect(303, `/danke/${order.id}`);
  },
};

Und auf der Danke-Seite dieselbe event_id im Browser — sie bringt die Klick-IDs und die Besucherkennung mit, die nur der Browser kennt:

svelte
<!-- src/routes/danke/[id]/+page.svelte -->
<script lang="ts">
  import { purchase } from "@trackdolphin/sdk";

  let { data } = $props();

  $effect(() => {
    purchase({ event_id: `order_${data.order.id}`, value: data.order.total, currency: "EUR" });
  });
</script>

Fällt das Tracking aus, ist die Bestellung trotzdem da. Andersherum kostet ein Ausfall bei uns dich einen Kunden — das darf nie passieren, deshalb das try/catch nach dem Geschäft.

5. Prüfen

Ruf eine Produktseite auf. Im Dashboard unter Einrichtung zählt der Eventzähler innerhalb weniger Sekunden hoch; unter Events siehst du jedes einzelne mit Empfangskanal und Zustellstatus je Plattform. Der Kauf erscheint dort einmal — mit beiden Quellen, Browser und Server, unter einer event_id.

Kommt nichts an:

  • Der Browser meldet 404 auf /td: Die Datei liegt nicht unter src/routes/td/+server.ts, oder ein handle-Hook fängt die Route ab.
  • Der Browser bekommt 202 statt 204: Die Route lebt, der Collector hat abgelehnt — die Ursache steht im Server-Log (meist eine falsche TD_ENDPOINT).
  • requireConsent: true, aber nie setConsent() aufgerufen: Die Events warten in der Warteschlange.

Rückfall, falls die Route einmal nicht antwortet

Mit fallbackEndpoint schickt das SDK das erste Event einer Sitzung per fetch an die Route und merkt sich die Antwort. Antwortet sie nicht oder mit 5xx, geht der Rest der Sitzung direkt an den Collector — ohne Tarnung, aber nicht verloren:

ts
init({ endpoint: "/td", fallbackEndpoint: "https://abc123.trdph.com/collect" });

Danach

Historie importieren — das zeigt dir in Zahlen, wie viel dein bisheriges Tracking übersehen hat. Alles Weitere zur API steht auf der SDK-Seite.