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

# Beispiele für Asynchronous Server Side Events

> Nutzlasten für serverseitige Ereignisse zusammensetzen und an die Facebook Conversion API oder einen Newsletter-Dienstleister übertragen.

Asynchronous Server Side Events übertragen Daten aus dem Shop an ein fremdes System, ohne dass der Käufer darauf wartet. Wie die Übertragung eingerichtet wird, steht in der Referenz. Diese Seite zeigt, wie die zu übertragende Nutzlast entsteht.

Wegweiser: [Asynchronous Server Side Events](https://dokumentation.websale.de/v8s/schnittstellen/marketing-seo-und-portale/ws-asse.md) · Referenz: [Abschnitt ASSE](https://dokumentation.websale.de/v8s/referenz/konfigurationen/shopkonfiguration-shop-config/externe-dienste-und-schnittstellen.md#asse)

## Vorab: ohne Einwilligung wird nichts gesendet

Die Beispiele auf dieser Seite übertragen Daten an Dienste Dritter, im zweiten Beispiel die IP-Adresse, die Browserkennung, Cookie-Werte und die gehashten Stammdaten des angemeldeten Kunden.

> [!WARNING]
>
> **Lösen Sie eine solche Übertragung erst aus, wenn der Besucher ihr zugestimmt hat.**
>
> Dass die Übertragung vom Server ausgeht und nicht aus dem Browser, ändert daran nichts. Entscheidend ist, welche Daten an wen fließen, nicht von wo.
>
> Klammern Sie `ASSE-Fire()` deshalb in die Prüfung auf die Einwilligung zur betreffenden Gruppe, wie sie der Consent-Layer bereitstellt. Der Parameter `ServiceCategory` im Abschnitt `<ASSE>` benennt die Kategorie, zu der das Ereignis gehört.

Ein Hashwert ist keine Anonymisierung. Eine mit SHA-256 gehashte E-Mail-Adresse ist genau dazu gedacht, beim Empfänger wieder einer Person zugeordnet zu werden. Das ist der Zweck des Verfahrens, und deshalb bleibt es eine Übermittlung personenbezogener Daten.

Referenz: [AC- (AgreementCookies)](https://dokumentation.websale.de/v8s/referenz/tags/ac-agreementcookies.md)

## Das gemeinsame Muster

Alle Beispiele setzen die Nutzlast in einem freien Parameter zusammen und übergeben ihn an `ASSE-Fire()`.

| Regel | Warum |
| - | - |
| `~DC-FPX_set(…)~` beginnt, `~DC-FPX_append(…)~` hängt an | der Parameter wird dadurch bei jedem Durchlauf frisch aufgebaut |
| innerhalb der Klammern stehen Tags als `$Tagname$` | in einem Tag-Argument gilt die Dollar-Schreibweise, nicht die Tilde |
| Texte laufen über `~DC-FPX_jsonencoding~` | maskiert Anführungszeichen und Sonderzeichen |
| Preise zwischen `~WS-DisablePriceAndNumberFormat~` und `~WS-EnablePriceAndNumberFormat~` | sonst kommt der Preis mit Tausendertrennzeichen und Komma an |
| vor der Nutzlast steht `$WS-DisableXSSProtectionOnce$` | hebt die Zeichenersetzung für diesen einen Aufruf auf |

> [!WARNING]
>
> Vergessen Sie das `_jsonencoding` bei keinem Text. Ein Produktname mit einem Anführungszeichen, ein Nachname mit einem Apostroph, und die Nutzlast ist kein gültiges JSON mehr. Der Empfänger verwirft dann die gesamte Übertragung, nicht nur das eine Feld. Bemerken würden Sie das erst, wenn die Zahlen im Zielsystem nicht mehr stimmen.
>
> Schalten Sie die Preisformatierung unmittelbar nach dem Preis wieder ein. Bleibt sie aus, erscheinen **alle** weiteren Preise auf dieser Seite unformatiert, also ohne Tausendertrennzeichen und mit Punkt statt Komma. In der bisherigen Beschreibung fehlt das Wiedereinschalten im zweiten Beispiel.
>
> Setzen Sie den Zeitpunkt mit `~DC-DateTime_set~`, bevor Sie `$DC-DateTime_unixtimestamp$` verwenden. Alle `DC-DateTime`-Tags beziehen sich auf den Zeitpunkt, den dieses Tag gesetzt hat. In der bisherigen Beschreibung fehlt es in allen Beispielen.

Referenz: [DC-FPX\_set()](https://dokumentation.websale.de/v8s/referenz/tags/dc/parameter.md#die-tags-im-uberblick) · [DC-FPX\_append](https://dokumentation.websale.de/v8s/referenz/tags/dc/parameter.md#die-tags-im-uberblick) · [DC-FPX\_jsonencoding](https://dokumentation.websale.de/v8s/referenz/tags/dc/parameter.md#die-tags-im-uberblick) · [ASSE-Fire()](https://dokumentation.websale.de/v8s/referenz/tags/asse.md#asse-fire) · [WS-DisableXSSProtectionOnce](https://dokumentation.websale.de/v8s/referenz/tags/ws/shop-seite-und-technik.md#die-tags-im-uberblick)

## Beispiel 1: Facebook Conversion API, Grundform

### Die Konfiguration

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<ASSE>
   <+Entry>
      ID              = fbconversionapi
      Endpoint        = https://graph.facebook.com/v10.0/PIXELID/events?access_token=ZUGRIFFSSCHLUESSEL
      Type            = POST
      ContentType     = application/json
      ServiceCategory = Tracking
      <DefinitionOfOk>
         <+ConditionGroup>
            <+Condition>
               Proof = HTTPStatusCode
               Type  = value
               Value = 200
            </+Condition>
         </+ConditionGroup>
      </DefinitionOfOk>
   </+Entry>
</ASSE>
```

Die Versionsnummer im Endpunkt, hier `v10.0`, gehört zur Schnittstelle des Anbieters und veraltet. Prüfen Sie beim Einrichten, welche Fassung aktuell unterstützt wird.

### PageView

Auf jeder Seite, auf der das Ereignis gemeldet werden soll:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~DC-DateTime_set~
~DC-FPFireJSON_set({"data":[{"event_name":"PageView","event_time": $DC-DateTime_unixtimestamp$)~
~DC-FPFireJSON_append(,"user_data": {"external_id": "$WS-SID$"}}]})~
~ASSE-Fire(fbconversionapi,$WS-DisableXSSProtectionOnce$$DC-FPFireJSON$)~
```

### ViewContent

Auf der Produktdetailansicht:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~DC-DateTime_set~
~DC-FPFireJSON_set({"data":[{"event_name":"ViewContent","event_time": $DC-DateTime_unixtimestamp$)~

~DC-FPPRName_set($PR-Name_StripHtml$)~
~DC-FPFireJSON_append(,"custom_data":{"content_name": "$DC-FPPRName_jsonencoding$")~

{CAT-PathData}
   ~DC-Int2_set(0)~
   ~DC-FPFireJSON_append(,"content_category": ")~
   {@CAT-PathRegular}
      ~DC-FPCatName_set($CAT-Name_StripHtml$)~
      {!DC-Int2(0)}~DC-FPFireJSON_append( > )~{/!DC-Int2(0)}
      ~DC-FPFireJSON_append($DC-FPCatName_jsonencoding$)~
      ~DC-Int2_inc~
   {/@CAT-PathRegular}
{/CAT-PathData}

~DC-FPFireJSON_append(","content_ids": ["$PR-ProdIndex$"])~
~DC-FPFireJSON_append(,"content_type": "product")~

~WS-DisablePriceAndNumberFormat~
~DC-FPFireJSON_append(,"value": $PR-Price$)~
~WS-EnablePriceAndNumberFormat~

~DC-FPFireJSON_append(,"currency": "$WS-Currency$")~
~DC-FPFireJSON_append(},"user_data": {"external_id": "$WS-SID$"})~
~DC-FPFireJSON_append(}]})~

~ASSE-Fire(fbconversionapi,$WS-DisableXSSProtectionOnce$$DC-FPFireJSON$)~
```

> [!NOTE]
>
> Der Zähler `DC-Int2` sorgt dafür, dass das Trennzeichen zwischen den Kategorieebenen nur **zwischen** den Einträgen steht und nicht vor dem ersten.
>
> Die bisherige Beschreibung schreibt die Klammerung dafür in das Argument des `_append`-Tags hinein. Das funktioniert, ist aber schwer zu lesen. Im Beispiel oben steht sie davor, mit demselben Ergebnis.

### AddToCart, InitiateCheckout und Purchase

Diese drei Ereignisse unterscheiden sich nur im Namen und in der Stelle, an der sie stehen.

| Ereignis | Template | Besonderheit |
| - | - | - |
| `AddToCart` | nach dem Hinzufügen zum Warenkorb | wie `ViewContent`, aber mit den `BASKET-PR-`-Tags der Position |
| `InitiateCheckout` | Beginn des Bestellablaufs | Schleife über alle Warenkorbpositionen, Gesamtwert aus `BASKET-OrderTotal` |
| `Purchase` | Bestelleingangsbestätigung | gleicher Aufbau wie `InitiateCheckout` |

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~DC-DateTime_set~
~DC-FPFireJSON_set({"data":[{"event_name":"InitiateCheckout","event_time": $DC-DateTime_unixtimestamp$)~
~DC-FPFireJSON_append(,"custom_data":{)~

{BASKET-PR-Data}
   ~DC-Int2_set(0)~
   ~DC-FPFireJSON_append("contents": [)~
   ~WS-DisablePriceAndNumberFormat~
   {@BASKET-PR-Data}
      {!DC-Int2(0)}~DC-FPFireJSON_append(,)~{/!DC-Int2(0)}
      ~DC-FPFireJSON_append({"id": "$BASKET-PR-Number$")~
      ~DC-FPFireJSON_append(,"quantity": $BASKET-PR-Quantity$,"item_price": $BASKET-PR-Price$})~
      ~DC-Int2_inc~
   {/@BASKET-PR-Data}
   ~WS-EnablePriceAndNumberFormat~
{/BASKET-PR-Data}

~DC-FPFireJSON_append(],"content_type": "product")~
~WS-DisablePriceAndNumberFormat~
~DC-FPFireJSON_append(,"value": $BASKET-OrderTotal$)~
~WS-EnablePriceAndNumberFormat~
~DC-FPFireJSON_append(,"currency": "$WS-Currency$")~
~DC-FPFireJSON_append(},"user_data": {"external_id": "$WS-SID$"})~
~DC-FPFireJSON_append(}]})~

~ASSE-Fire(fbconversionapi,$WS-DisableXSSProtectionOnce$$DC-FPFireJSON$)~
```

Für `Purchase` ändern Sie nur `"event_name":"Purchase"`.

> [!NOTE]
>
> Für `AddToCart` wird der Produktname aus dem Warenkorb geholt. Dafür gibt es kein Tag mit eingebautem HTML-Entfernen, deshalb geht es über zwei Schritte:
>
> ```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
> ~DC-FPPRName_set($BASKET-PR-Name$)~
> ~DC-FPPRName_set($DC-FPPRName_StripHTML$)~
> ```

Referenz: [CAT-PathData](https://dokumentation.websale.de/v8s/referenz/tags/cat/navigation-und-kategoriebaum.md#cat-pathdata) · [CAT-PathRegular](https://dokumentation.websale.de/v8s/referenz/tags/cat/navigation-und-kategoriebaum.md#die-tags-im-uberblick) · [BASKET-PR-Data](https://dokumentation.websale.de/v8s/referenz/tags/basket/mehrfach-lieferadressen-und-belegexemplare.md#basket-pr-d) · [BASKET-OrderTotal](https://dokumentation.websale.de/v8s/referenz/tags/basket/warenkorbsummen.md#warenwert-und-zwischensumme) · [WS-SID](https://dokumentation.websale.de/v8s/referenz/tags/ws/shop-seite-und-technik.md#die-tags-im-uberblick) · [WS-Currency](https://dokumentation.websale.de/v8s/referenz/tags/ws/warenkorb-preise-waehrung-und-bonus.md#die-tags-im-uberblick)

## Beispiel 2: zusätzlich mit Cookies, IP-Adresse und Kundendaten

Die zweite Fassung ergänzt die Nutzlast um Angaben, mit denen der Empfänger den Besucher wiedererkennen kann.

### Die Hash-Kennung anlegen

Die Kundendaten werden vor der Übertragung gehasht. Den Schlüssel dafür legen Sie in der `shop.config` an:

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<DesignControl>
   <+Hash>
      ID     = fbconversionhash
      Secret = <ein eigener, zufällig erzeugter Schlüssel>
   </+Hash>
   ...
</DesignControl>
```

> [!WARNING]
>
> Erzeugen Sie den Schlüssel selbst und übernehmen Sie keinen aus einer Beschreibung. Ein Schlüssel, der in einer Anleitung steht, ist kein Geheimnis mehr.

### Die Ergänzungen in der Nutzlast

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~DC-FPFireJSON_append(,"action_source": {!WS-AppVersion}"website"{/!WS-AppVersion}{WS-AppVersion}"other"{/WS-AppVersion})~
~DC-FPFireJSON_append(,"event_source_url": "$URL-Homepage$$WS-RequestURI$")~
~DC-FPFireJSON_append(,"user_data": {)~
~DC-FPFireJSON_append("client_user_agent": "$WS-UserAgent$")~
~DC-FPFireJSON_append(,"client_ip_address": "$WS-ClientIPAddr$")~

~CheckCookie-TouchData(_fbc)~
{CheckCookie-DataOK}
   ~DC-FPFireJSON_append(,"fbc": "$CheckCookie-Data$")~
{/CheckCookie-DataOK}

~CheckCookie-TouchData(_fbp)~
{CheckCookie-DataOK}
   ~DC-FPFireJSON_append(,"fbp": "$CheckCookie-Data$")~
{/CheckCookie-DataOK}

{ST-LoggedIn}
   ~DC-FPUserUserIndex_set($A-UserIndex$)~
   ~DC-FPFireJSON_append(,"external_id": "$DC-FPUserUserIndex_hash(sha256,hex,fbconversionhash)$")~

   {A-E-Mail}
      ~DC-FPUserEMail_set($A-E-Mail$)~
      ~DC-FPFireJSON_append(,"em": "$DC-FPUserEMail_hash(sha256,hex,fbconversionhash)$")~
   {/A-E-Mail}

   <!-- nach demselben Muster: ph, ge, db, ln, fn, ct, zp, country -->
{/ST-LoggedIn}

~DC-FPFireJSON_append(})~
```

| Feld | Inhalt |
| - | - |
| `client_user_agent`, `client_ip_address` | Browserkennung und IP-Adresse des Besuchers |
| `fbc`, `fbp` | Cookie-Werte, die der Dienst selbst gesetzt hat |
| `external_id` | der Kundenindex, gehasht |
| `em`, `ph`, `ge`, `db`, `ln`, `fn`, `ct`, `zp`, `country` | E-Mail, Telefon, Anrede, Geburtsdatum, Name, Ort, Postleitzahl und Land, jeweils gehasht |

> [!WARNING]
>
> Jedes einzelne dieser Felder ist ein personenbezogenes Datum, und zusammen ergeben sie ein vollständiges Kundenprofil. Für diese Fassung gilt der Hinweis vom Anfang der Seite in verschärfter Form: ohne ausdrückliche Einwilligung gar nicht.
>
> Nehmen Sie außerdem nur die Felder auf, die der Empfänger tatsächlich braucht. Geburtsdatum und Telefonnummer sind für eine Reichweitenmessung in aller Regel entbehrlich.

Jede Klammerung wie `{A-E-Mail}` sorgt dafür, dass das Feld nur erscheint, wenn es gefüllt ist. Ein Hashwert eines leeren Felds wäre für alle Kunden derselbe und damit nicht nur nutzlos, sondern irreführend.

Referenz: [DC-FPX\_hash()](https://dokumentation.websale.de/v8s/referenz/tags/dc/parameter.md#die-tags-im-uberblick) · [CheckCookie-](https://dokumentation.websale.de/v8s/referenz/tags/check.md) · [WS-ClientIPAddr](https://dokumentation.websale.de/v8s/referenz/tags/ws/shop-seite-und-technik.md#die-tags-im-uberblick) · [WS-UserAgent](https://dokumentation.websale.de/v8s/referenz/tags/ws/shop-seite-und-technik.md#die-tags-im-uberblick) · [ST-LoggedIn](https://dokumentation.websale.de/v8s/referenz/tags/st/seitenzustand-und-navigation.md)

## Beispiel 3: Newsletter-Anmeldung an einen Dienstleister übergeben

Der Besucher trägt sich über ein INQUIRY-Formular ein, und das Ereignis meldet die Anmeldung an den Newsletter-Dienstleister.

```text theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
<ASSE>
   <+Entry>
      ID              = newslettersubscribe
      Endpoint        = https://api.anbieter.example/forms/submit/XXXX?type=subscribe
      Type            = POST
      ContentType     = application/json
      ServiceCategory = Tracking
      <AdditionalHeaders>
         <+HttpHeader>
            Name  = Accept
            Value = application/json
         </+HttpHeader>
      </AdditionalHeaders>
      <DefinitionOfOk>
         <+ConditionGroup>
            <+Condition>
               Proof = HTTPStatusCode
               Type  = value
               Value = 201
            </+Condition>
         </+ConditionGroup>
         <+ConditionGroup>
            <+Condition>
               Proof = HTTPStatusCode
               Type  = value
               Value = 200
            </+Condition>
         </+ConditionGroup>
      </DefinitionOfOk>
   </+Entry>
</ASSE>
```

Zwei `<+ConditionGroup>`-Abschnitte sind untereinander **oder**-verknüpft. Der Dienst antwortet je nach Fall mit `200` oder `201`, und beides soll als Erfolg gelten.

Im Template des Formulars:

```html theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/websale.json"]}}
~DC-FPNLMail_set($A-EMail_value$)~
~DC-FPNLFirst_set($A-FirstName_value$)~
~DC-FPNLLast_set($A-LastName_value$)~

~DC-FPFireJSON_set({"recipient":{)~
~DC-FPFireJSON_append("email":"$DC-FPNLMail_jsonencoding$")~
~DC-FPFireJSON_append(,"first_name":"$DC-FPNLFirst_jsonencoding$")~
~DC-FPFireJSON_append(,"last_name":"$DC-FPNLLast_jsonencoding$")~
~DC-FPFireJSON_append(},"lists":[],"captcha":{}})~

~ASSE-Fire(newslettersubscribe,$WS-DisableXSSProtectionOnce$$DC-FPFireJSON$)~
```

> [!WARNING]
>
> **Die bisherige Beschreibung hat an dieser Stelle zwei Fehler.**
>
> Erstens stehen die Tags dort in der Tilde-Schreibweise innerhalb des `_append`-Arguments. In einem Tag-Argument gilt die Dollar-Schreibweise, so wie in allen übrigen Beispielen dieser Seite.
>
> Zweitens fehlt die Maskierung. Gerade hier wiegt das schwer, denn es handelt sich um Eingaben aus einem Formular. Ein Nachname mit Apostroph genügt, und die Anmeldung geht verloren. Deshalb der Umweg über drei freie Parameter mit `_jsonencoding`.
>
> Eine Newsletter-Anmeldung braucht eine Bestätigung per E-Mail. Übergeben Sie die Adresse an den Dienstleister so, dass dieser das Bestätigungsverfahren durchführt, und behandeln Sie den Empfänger erst danach als angemeldet.

## Die Alternative: dieselbe Nutzlast mit den JSON-Tags

Alles auf dieser Seite lässt sich auch mit den Tags der JSON-Schnittstelle bauen. Dann setzt der Shop die Klammern und maskiert die Werte, und beide Fehlerquellen aus den Warnungen oben entfallen.

Für neue Umsetzungen ist das der empfehlenswerte Weg. Die Fassung mit `DC-FPX_append` bleibt nachvollziehbar, solange nur Zahlen und Kennungen übertragen werden.

Anwendungsbeispiel: [Beispiele zur JSON-Schnittstelle](https://dokumentation.websale.de/v8s/anwendungsbeispiele/appex-json-schnittstelle-beispiele.md) · Referenz: [EJD- (JSON-Daten)](https://dokumentation.websale.de/v8s/externe-dienste/json-schnittstelle.md#die-beiden-tag-familien)

## Verwandte Themen

* Wegweiser: Asynchronous Server Side Events
* Anwendungsbeispiel: [Beispiele zur JSON-Schnittstelle](https://dokumentation.websale.de/v8s/anwendungsbeispiele/appex-json-schnittstelle-beispiele.md)
* Wegweiser: [Integration eines INQUIRY-Formulars](https://dokumentation.websale.de/v8s/formulare-fuer-kundenanfragen/formulare-fuer-kundenanfragen.md)
* Referenz: [AC- (AgreementCookies)](https://dokumentation.websale.de/v8s/referenz/tags/ac-agreementcookies.md)


## Related topics

- [Anwendungsbeispiele](https://dokumentation.websale.de/v8s/anwendungsbeispiele/anwendungsbeispiele.md)
- [WS-ASSE: Asynchronous Server Side Events](https://dokumentation.websale.de/v8s/schnittstellen/marketing-seo-und-portale/ws-asse.md)
- [general - Allgemeine Shopeinstellungen](https://dokumentation.websale.de/konfiguration/general-allgemeine-shopeinstellungen.md)
- [Beispiele zur JSON-Schnittstelle](https://dokumentation.websale.de/v8s/anwendungsbeispiele/appex-json-schnittstelle-beispiele.md)
- [ASSE-Schnittstelle (Server-Side-Events)](https://dokumentation.websale.de/schnittstellen/asse-schnittstelle-server-side-events.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.