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

# Verteiltes Tracing für Browser

> Sehen Sie, wie eine fehlgeschlagene Anfrage im Browser mit dem Back-end-Trace verbunden ist, den sie ausgelöst hat, sodass der Fehler und die dahinterliegende Server-Arbeit als ein einziger Trace lesbar sind.

export const Compatibility = ({versions = [], label = "Available in"}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const defaultPillStyle = {
    borderColor: "#d4d4d8",
    background: "#f4f4f5",
    color: "#3f3f46"
  };
  const pillStyles = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#d8b4fe",
      color: "#6b21a8"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#5eead4",
      color: "#115e59"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#86efac",
      color: "#166534"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#93c5fd",
      color: "#1e40af"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fca5a5",
      color: "#991b1b"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fdba74",
      color: "#9a3412"
    }
  };
  const getPillStyle = name => ({
    ...defaultPillStyle,
    ...pillStyles[name] || ({})
  });
  return <div className="not-prose my-4 rounded-lg border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm dark:border-white/10 dark:bg-white/5">
      <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
        <span className="font-semibold text-zinc-700 dark:text-zinc-200">
          {label}:
        </span>
        {versions.map((v, i) => <span key={`${v.name}-${v.version}-${i}`} className="inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium" style={getPillStyle(v.name)}>
            <span>{v.name}</span>
            <span className="opacity-70">
              {v.version}
              {v.exact ? "" : "+"}
            </span>
          </span>)}
      </div>
    </div>;
};

<Compatibility versions={[{ name: "AppSignal for Browser", version: "1.0.0-beta.7" }]} />

<Note>
  Browser monitoring ist ein Beta-Feature von [AppSignal Labs](/labs). Das Paket
  `@appsignal/browser` wird unter dem `beta`-Tag auf npm veröffentlicht, und
  seine Konfiguration und API können sich zwischen Beta-Releases noch ändern.
  Teilen Sie Ihr Feedback in unserer
  [Discord-Community](https://discord.gg/EjF6ykYx63).
</Note>

Eine Checkout-Seite meldet `POST https://api.example.com/orders: HTTP 503`. Sie wissen, dass der Order-Request fehlgeschlagen ist, aber nicht warum. Der Order-Service hat möglicherweise vier Sekunden auf eine Datenbanksperre gewartet, bevor er 503 zurückgab. [Verteiltes Tracing](/distributed-tracing) lässt Sie diesen Request vom Browser bis in den Order-Service verfolgen.

Um den Browser-Fehler mit der Arbeit im Order-Service zu verbinden, richten Sie beide Seiten ein:

1. **Browser:** Fügen Sie Ihre API-URL-Muster zu `tracePropagationTargets` hinzu. Passende Requests tragen einen `traceparent`-Header. Eine 5xx-Response oder ein qualifizierender Timeout wird zu einem Browser-Fehler.
2. **Empfangender API-Service:** Instrumentieren Sie dessen HTTP-Server, damit er `traceparent` liest und Spans über einen gehosteten AppSignal-Collector meldet. Verwenden Sie eine unterstützte Integration oder eine OpenTelemetry-Instrumentierung für sein Framework.

Schritt 1 allein meldet nur den Browser-Fehler. Seine Trace-Timeline bleibt leer, bis der Order-Service in Schritt 2 instrumentiert ist, denn die Server-Spans stammen aus dieser Instrumentierung, nicht aus dem Browser-SDK. Beide Schritte sind nötig, um den Request als einen Trace zu sehen.

<Note>
  Verteiltes Tracing ist ein Beta-Feature von [AppSignal Labs](/labs). Das Browser-SDK benötigt keinen Collector. Der empfangende Service benötigt einen [gehosteten AppSignal-Collector](/collector/hosted-vs-self-hosted#hosted-collector) für seine Spans.
</Note>

<h2 id="before-you-start">
  Bevor Sie beginnen
</h2>

Wählen Sie die Einrichtung für den Service, der den Browser-Request empfängt. Dessen HTTP-Server-Integration muss `traceparent` lesen, und der Service muss Spans über einen [gehosteten AppSignal-Collector](/collector/hosted-vs-self-hosted#getting-started) senden:

* **FastAPI:** Installieren Sie [`opentelemetry-instrumentation-fastapi`](/python/instrumentations/fastapi) und verwenden Sie den [Python-Collector-Modus](/python/configuration/collector).
* **Rails:** Verwenden Sie die [Gems `appsignal` und `appsignal-opentelemetry`](/ruby/configuration/collector#installing-the-opentelemetry-gems) im Collector-Modus. Die [Rails-Integration](/ruby/integrations/rails) liest eingehende Traces.
* **Go oder individuelles OpenTelemetry:** Instrumentieren Sie Ihren HTTP-Server und konfigurieren Sie die Trace-Context-Propagation. Siehe [Verfügbarkeit und Einrichtung](/distributed-tracing#availability-and-setup).

<h2 id="enable-it">
  Aktivieren
</h2>

Fügen Sie für jeden API-Host und -Pfad ein Muster zu `tracePropagationTargets` hinzu. Die standardmäßig leere Liste lässt das Tracing ausgeschaltet:

<CodeGroup>
  ```js appsignal.js theme={null}
  import { init } from "@appsignal/browser";

  init({
    key: "<YOUR_FRONTEND_API_KEY>",
    endpoint: "https://appsignal-endpoint.net",
    appVersion: "<YOUR_APP_REVISION>",
    // Your API hosts, matched against host + pathname
    tracePropagationTargets: ["api.example.com/**"],
    // How this front end is named in a trace. Defaults to "Browser"
    serviceName: "Checkout UI",
  });
  ```
</CodeGroup>

Muster werden gegen den Host und Pfad jedes `fetch`- und `XMLHttpRequest`-Aufrufs abgeglichen. Sie ignorieren das Schema und den Query-String. Verwenden Sie `*` innerhalb eines Pfadsegments oder `**` über Segmente hinweg. Geben Sie sowohl einen Host als auch einen Pfad an:

| Muster | Trifft auf |
| - | - |
| `api.example.com/**` | Jeden Request an `api.example.com` auf dem Standardport. |
| `api.example.com:8443/**` | Jeden Request an `api.example.com` auf Port 8443. Geben Sie den Port an, wenn er nicht der Standard ist. |
| `*.example.com/**` | Jeden Request an eine Subdomain von `example.com`. |
| `api.example.com/v1/**` | Requests unter `/v1` auf `api.example.com`. |
| `api.example.com` | Nichts. Es hat keinen Pfad, fügen Sie also `/**` hinzu. |
| `/api/**` | Nichts. Es hat keinen Host. |
| `**/api/**` | Diesen Pfad auf jedem Host, auch bei Drittanbietern, die Sie nie tracen wollten. Vermeiden Sie das. |

In der Trace-Timeline beschriftet `serviceName` den Browser-Fehler-Span. `Checkout UI` kennzeichnet zum Beispiel Fehler aus Ihrem Checkout-Front-end. Der Standard ist `Browser`. Verwenden Sie für jedes Front-end, das Sie überwachen, einen eigenen Namen. Das SDK sendet den Namen mit jedem Fehlerbericht.

Der [Installationsassistent des Browser-SDK](https://appsignal.com/redirect-to/organization?to=sites/new/browser) bietet **Verteiltes Tracing** als Option an. Es ist standardmäßig ausgeschaltet. Wählen Sie es aus, fügt das dem Browser-Snippet `tracePropagationTargets: ["api.example.com/**"]` hinzu. Ersetzen Sie den Beispiel-Host durch Ihren API-Host und [instrumentieren Sie anschließend den empfangenden Service](#before-you-start). Der Assistent installiert oder konfiguriert diesen Service nicht.

Um die Propagation zu prüfen, laden Sie eine Seite, die Ihre API aufruft, und untersuchen Sie den Request im Network-Panel Ihres Browsers. Ein passender Request sollte einen `traceparent`-Header tragen. Prüfen Sie anschließend einen fehlgeschlagenen Request in AppSignal, um zu sehen, ob Back-end-Spans in seinem Trace erscheinen.

Bei einer Cross-Origin-API, etwa `api.example.com`, aufgerufen von `www.example.com`, sendet der Browser möglicherweise vor dem Request einen [CORS-Preflight](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request). Erlauben Sie `traceparent` in der Response Ihrer API auf den Preflight. Sonst blockiert der Browser den Request möglicherweise:

<CodeGroup>
  ```http HTTP theme={null}
  Access-Control-Allow-Headers: content-type, traceparent
  ```
</CodeGroup>

Das SDK fügt einem Request im `no-cors`-Modus keinen Header hinzu, weil der Browser ihn entfernen würde. Diese Requests werden nie als fehlgeschlagene Requests gemeldet.

<h2 id="what-is-reported">
  Was gemeldet wird
</h2>

Das SDK meldet diese Ergebnisse für einen passenden Request, der einen `traceparent`-Header gesendet hat:

* **Eine 5xx-Response** wird als `HTTPError` gemeldet.
* **Ein Timeout** wird als `TimeoutError` gemeldet. Das ist ein `fetch`, der mit einem `TimeoutError` abgelehnt wird, wie es ein durch `AbortSignal.timeout()` begrenzter tut. Es ist auch ein `XMLHttpRequest`, dessen `timeout` auslöst. Der Server hat einen Request mit Timeout möglicherweise empfangen und in einem Trace erfasst.

Die Meldung benennt den Request und sein Ergebnis, zum Beispiel `POST https://api.example.com/orders: HTTP 503` oder `GET https://api.example.com/orders: timed out`. Neben allem, was ein [gewöhnlicher Browser-Fehler](/browser/error-tracking#what-is-reported) trägt, enthält der Bericht:

* **Den Request**, als `params.request`: die `url`, die `method`, den `status`, wenn eine Response eingetroffen ist, und die `duration_ms`. Query-Parameter werden gemäß Ihrer [Allowlist](/browser/privacy#urls-and-query-parameters) aus der URL entfernt.
* **Den Span**: die Trace-ID und Span-ID aus dem `traceparent` des Requests, mit seiner Startzeit und Dauer. AppSignal baut daraus den Span des Browsers, sodass er den Request so abdeckt, wie der Browser ihn gesehen hat. Nach einem Timeout können die Spans des Back-ends länger laufen als der Span des Browsers.
* **Den Servicenamen**, den Sie gesetzt haben, oder `Browser`.

Für Folgendes wird nichts gemeldet:

* Einen erfolgreichen Request. Der Header wird gesendet, aber der Browser bleibt still, sodass der Back-end-Trace für sich steht.
* Eine 4xx-Response. Das SDK stuft sie nicht als fehlgeschlagenen Request für Tracing ein.
* Einen Request, den der Browser nicht zustellen konnte: abgewiesen, DNS-Fehler oder von einer Extension blockiert. Kein Server hat ihn verarbeitet, es gibt also keinen Back-end-Trace, dem er beitreten könnte.
* Einen Timeout, während das Gerät offline ist, was nichts über das Back-end aussagt.
* Einen Request, den Ihr Code abgebrochen hat.

Diese Requests können trotzdem einen [Netzwerk-Breadcrumb](/browser/breadcrumbs#reading-network-breadcrumbs) hinterlassen, sofern sie nicht auf `privacy.networkBlocklist` passen oder die Breadcrumb-Erfassung deaktiviert ist. Ein Breadcrumb für einen Request, der den Context propagiert hat, enthält dessen Trace-ID.

Ein fehlgeschlagener Request durchläuft dieselbe Pipeline wie jeder andere Fehler. `errors.enabled`, `errors.sampleRate`, die [Rate-Limits](/browser/error-tracking#rate-limits) und die Deduplizierung von Wiederholungen gelten alle. `beforeError` erhält ihn als `HTTPError` oder `TimeoutError`, mit dem Request unter `context.request`. Sie können ihn dort verwerfen oder redigieren. Ein Request, der auf `privacy.networkBlocklist` passt, wird nie gemeldet.

Das SDK vermeidet es, dieselbe `fetch`-Ablehnung zweimal zu melden, wenn sie auch einen Unhandled-Rejection-Handler oder `captureError()` erreicht. Wenn Ihr Code nach einer 500-Response einen neuen Fehler wirft, hat dieser Fehler seinen eigenen Trace. Der fehlgeschlagene Request bleibt ein separater Bericht.

<h2 id="reading-it-in-appsignal">
  In AppSignal lesen
</h2>

Fehlgeschlagene Requests erscheinen in der Errors-Ansicht des Browser-Bereichs als `HTTPError`- und `TimeoutError`-Issues. Sie werden nach der Route gruppiert, auf der sich der Nutzer befand, wie jeder andere Front-end-Fehler. Mehr dazu unter [Front-end-Fehler in AppSignal](/browser-monitoring/errors).

Öffnen Sie ein Issue, um seine Meldung, Breadcrumbs und Tags zu sehen. Wählen Sie auf der vollständigen Issue-Seite **Traces**. Wählen Sie dann **Fullscreen** in der Karte **Trace timeline**, um die unten gezeigte Ansicht zu öffnen. Wenn die Vorschau Spans auslässt, lautet die Schaltfläche **All spans**. Im Seitenpanel der Browser Errors führt **Open full trace page** Sie zur Issue-Seite.

In der Vollbild-Trace-Timeline beschriftet `Browser` den Service des Browser-Spans. Wählen Sie diesen Span, um die Request- und Fehlerdetails zu sehen.

Dieses Beispiel zeigt eine Produktseite, auf der `GET /api/boom/` HTTP 500 zurückgab. In der [Trace-Timeline](/trace-page#trace-timeline) können Sie den fehlgeschlagenen Request vom Browser bis in den Django-Service verfolgen:

* `Browser` zeigt einen `HTTPError` auf `/product/chocolate-stroopwafel` (85 ms). Die Details des ausgewählten Spans zeigen die Request-URL und die HTTP-500-Response.
* Darunter zeigt `django` `GET api/boom/` mit einem `RuntimeError` (81 ms).
* Der Django-Request enthält zwei `SELECT`-Spans und einen `POST`-Span, mit ihren Dauern.

<Frame caption="Der fehlgeschlagene Browser-Request und die zugehörigen Django-Spans in einem Trace.">
  <img src="https://mintcdn.com/appsignal-715f5a51/Dd6j9BLrZGGvnmnD/assets/images/screenshots/browser/distributed-tracing-trace-timeline.png?fit=max&auto=format&n=Dd6j9BLrZGGvnmnD&q=85&s=7bee604479952a0a8d48422852810a59" alt="Trace-Timeline, die einen 85 ms langen Browser-HTTPError für GET /api/boom/ (HTTP 500) mit einem 81 ms langen Django-RuntimeError verbindet, mit SELECT- und POST-Child-Spans." width="1395" height="874" data-path="assets/images/screenshots/browser/distributed-tracing-trace-timeline.png" />
</Frame>

Die [Service-Map](/trace-page#service-map) zeigt den gesamten Trace von Anfang bis Ende: den Fehler im Django-Service, verbunden mit dem fehlgeschlagenen Request im Browser, der ihn ausgelöst hat.

<Frame caption="Die Service-Map für denselben Trace: der Back-end-Fehler, verbunden mit dem Browser-Fehler, der ihn ausgelöst hat.">
  <img src="https://mintcdn.com/appsignal-715f5a51/Dd6j9BLrZGGvnmnD/assets/images/screenshots/browser/distributed-tracing-service-map.png?fit=max&auto=format&n=Dd6j9BLrZGGvnmnD&q=85&s=34693ed41ff4344c9a80827fbd60f3fd" alt="Trace-Service-Map mit zwei Boxen, Browser und django, beide mit einem Fehler markiert, verbunden durch eine 81 ms lange Kante." width="1049" height="575" data-path="assets/images/screenshots/browser/distributed-tracing-service-map.png" />
</Frame>

<h2 id="joining-a-trace-your-code-started">
  Einem Trace beitreten, den Ihr Code gestartet hat
</h2>

Ihre Anwendung setzt möglicherweise bereits einen gültigen `traceparent` auf einen Request, zum Beispiel über ein OpenTelemetry-Browser-SDK. AppSignal für Browser lässt diesen Header dann unangetastet, und ein fehlgeschlagener Request tritt dem Trace bei, den Ihr Code gestartet hat. Das gilt gleichermaßen für `fetch` und `XMLHttpRequest`.

Öffnen Sie im Tab **Traces** des Issues die [Trace-Timeline](/trace-page#trace-timeline) im Vollbildmodus, um die Back-end-Arbeit zu untersuchen.


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