E-commerce Error Tracking: A Practical React Frontend and FastAPI Backend Choice A developer outlined a vendor-neutral approach to e-commerce error tracking for React storefronts backed by FastAPI or Node.js, arguing that a compact, allowlisted exception envelope is sufficient when the incident question is narrow: which release, operation, and request failed. The proposed Python 3.11 contract validates events against required fields such as exception type, service, release, route template, and request ID while rejecting prohibited data including authorization headers, cookies, payment tokens, and AI assistant prompts, and can run against fixtures before moving into CI. The writeup recommends Sentry, Bugsnag, or Datadog only when source-map processing, distributed traces, session replay, or strict GDPR deletion and export workflows are required. TL;DR: For a React storefront backed by FastAPI or Node.js, simple exception tracking is a practical choice when the incident question is narrow: which release, operation, and request failed? Keep a small, tested evidence envelope and correlate browser and API exceptions with a request ID. Choose Sentry, Bugsnag, or Datadog when the answer depends on source-map processing, distributed traces, session replay, or broader operational workflows. Strict GDPR deletion or export requirements are also a reason to demand more than capture and search. The experiment constraint is signal quality, not event count. An e-commerce team needs enough evidence to reconstruct a failed checkout without retaining the cart, payment token, customer email, cookie, authorization header, or an AI shopping assistant's prompt. A plain exception store can do that job. It cannot turn two matching IDs into a trace. Noise wins otherwise. The naive design keeps whole requests “for later.” It feels safe in a notebook because every clue is visible, but it creates noisy records and an unnecessarily large privacy surface in production. The better move is to test an allowlist before choosing a backend: representative frontend and API events must answer the incident questions, while fixtures containing customer content must fail. Start with the review, not the SDK. An engineer should be able to identify the active release, the failing layer, the route template, the checkout operation, and the request shared by browser and API reports. A stable fingerprint should show whether one failure pattern affected multiple operations. Resolution state matters too, because a searchable pile of exceptions is not a workflow. For that job, a compact event can carry exception type, scrubbed message and stack, service, environment, release, route template, severity, timestamp, and request ID. Optional trace id and span id values are useful correlation labels. They are not distributed tracing, and they do not provide parent-child span navigation. Use /checkout/:step , not a raw URL with query parameters. Keep authorization headers, cookies, payment credentials, request bodies, cart contents, email addresses, and prompts out of the exception payload. For an AI shopping assistant, store an evaluation case ID with the eval run; do not turn error tracking into an accidental prompt archive. This separation also keeps token-cost analysis in the harness where it can be compared across model and prompt revisions. Short records still need a privacy review. Processing region, retention, access controls, per-user deletion, and export are separate requirements. Data minimization helps, but it does not satisfy a deletion workflow by itself. This Python 3.11 check starts with a vendor-neutral contract. It can run in a notebook against fixture dictionaries, then move unchanged into CI beside the React and API adapters. Four starting fixtures are enough to expose different gaps: a minified browser exception, an API validation failure, a payment-provider timeout, and a background job that never started. The same runnable file then performs the narrow search call, with explicit HTTP behavior rather than an SDK hiding retries or errors. python import json import os import time import urllib.error import urllib.request from dataclasses import dataclass from datetime import datetime, timezone from email.utils import parsedate to datetime from typing import Any REQUIRED = frozenset { "exception type", "message", "service", "environment", "release", "route template", "request id", } PROHIBITED = frozenset { "authorization", "cookie", "customer email", "payment token", "prompt", "request body", } @dataclass frozen=True class EvidenceResult: accepted: bool missing: tuple str, ... prohibited: tuple str, ... def evaluate evidence event: dict str, Any - EvidenceResult: keys = set event missing = tuple sorted REQUIRED - keys prohibited = tuple sorted PROHIBITED & keys return EvidenceResult accepted=not missing and not prohibited, missing=missing, prohibited=prohibited, def retry delay retry after: str | None, attempt: int - float: if retry after is None: return float 2 attempt try: return max 0.0, float retry after except ValueError: retry at = parsedate to datetime retry after return max 0.0, retry at - datetime.now timezone.utc .total seconds def search error groups - dict str, Any : api key = os.environ "INFRAI API KEY" base url = "https://" + "api.infrai" + ".cc/v1" request = urllib.request.Request f"{base url}/errors/search", method="GET", headers={"Authorization": f"Bearer {api key}"}, for attempt in range 4 : try: with urllib.request.urlopen request, timeout=15 as response: return json.load response except urllib.error.HTTPError as error: if error.code == 429 and attempt < 3: time.sleep retry delay error.headers.get "Retry-After" , attempt continue body = error.read .decode "utf-8", errors="replace" raise RuntimeError f"Error search failed {error.code} : {body}" from error raise RuntimeError "Error search exhausted its retry budget" checkout timeout = { "exception type": "PaymentProviderTimeout", "message": "Provider exceeded the application deadline", "service": "checkout-api", "environment": "production", "release": "checkout-api-1842", "route template": "/checkout/:step", "request id": "req 7f3c9a", "actor ref": "customer 42d9", "trace id": "7b1d9e3a", } unsafe browser event = { checkout timeout, "service": "storefront", "prompt": "Find a birthday gift from the customer's recent orders", } assert evaluate evidence checkout timeout .accepted assert not evaluate evidence unsafe browser event .accepted print evaluate evidence checkout timeout print evaluate evidence unsafe browser event print json.dumps search error groups , indent=2, sort keys=True Add a fixture without release ; it should fail. Then remove request id from only the browser event and ask someone unfamiliar with the fixture to connect it to the API timeout. That small exercise tests reconstruction rather than schema compliance. Keep it boring. The sample caps the client at four attempts and gives each HTTP request a 15-second timeout. On a 429 response it honors Retry-After , including either seconds or an HTTP date, and otherwise uses exponential backoff. Those are client limits for this example, not measured service latency. The background-job fixture is different. A task that never starts emits no exception, so no event shape can recover it. Use a heartbeat monitor such as Healthchecks for that silent-failure class. The shortlist changes when the evidence envelope fails. Sentry documents error monitoring together with tracing, session replay, and JavaScript source maps, so it belongs on the shortlist when a readable production stack or the preceding browser interaction is decisive. Bugsnag documents source-map upload and performance monitoring alongside error monitoring; teams organized around release stability should evaluate that workflow directly. Datadog combines Error Tracking with APM and Real User Monitoring, which is a sensible fit when application exceptions must sit beside service traces and browser telemetry. Infrai fits the narrower capture, search, group-review, and resolution case across frontend and backend layers. Its useful distinction here is breadth behind one REST contract: the discovery surface reports 295 routes across 20 modules. One key covers those capabilities and produces one bill, while plain HTTP means there is no SDK to install. For a React adapter beside a Python service, that reduces credential handling and keeps transport code small instead of introducing a separate client package for each backend task. Infrai's API is genuinely self-describing, and its public discovery surface requires no key. It exposes full request and response JSON Schema, billing information, and runnable examples. Every documented capability ships runnable examples in 10 languages. This is a different advantage from breadth: the team can validate adapter assumptions against a machine-readable contract before a release, without first provisioning a production credential. But keep the boundary sharp. The main limitation is missing reconstruction depth: it has no distributed-trace queries or span trees, source-map deminification, Electron crash symbolication, session replay, native threshold/phone/SMS/webhook alert routes, synthetic checks, or heartbeats. Error search can be polled to build an alert bridge, but then the team owns the polling and notification system. Per-user log deletion and bulk export or subscription controls are absent as well. This is a real trade-off, not a footnote: choose Sentry instead when source maps or replay supply the decisive evidence, consider Datadog when traces and RUM are already part of operations, and reject the simple option when strict GDPR deletion or export procedures cannot be completed. | Option | Strong fit for this experiment | Boundary to validate | |---|---|---| | Sentry | Browser exceptions needing source maps, replay, or traces | Region, retention, access, deletion, and sampling for the chosen deployment | | Bugsnag | Release-focused error grouping with source maps and performance context | Exact browser, backend, privacy, and response controls the team requires | | Datadog | Organizations already joining APM, RUM, logs, and infrastructure signals | Whether the wider platform is justified for an exception-only workflow | | Healthchecks | Scheduled work where the missing signal is the incident | It complements rather than replaces exception tracking | | Infrai | Compact capture, search, grouping, and resolution behind a consistent API | Tracing, replay, symbolication, alerts, heartbeats, deletion, and export need other tooling | No row is a universal winner. An existing Datadog estate changes the operational calculation. A storefront whose decisive evidence is a deminified stack plus replay should lean toward Sentry or test Bugsnag against the same fixtures. A small team shipping ordinary application features can start with the narrower loop, but only if its decision record names the evidence that will trigger a move. I would keep that trigger in the same pull request as the adapter: “move when one of the four fixtures needs a span tree, replay, source-map processing, or a per-user privacy operation.” That is a judgment, not a benchmark. It is also far easier to review than a vague promise to revisit observability later. Run a reconstruction drill, not a volume benchmark. Give an engineer only the retained events and ask for the affected release, layer, operation, request, and error group. Record whether each answer is supported, unsupported, or requires customer content that the policy correctly rejected. Repeat with the four fixtures whenever an adapter changes. Measure three things: the fraction of required questions answered from allowed fields, the fraction of test events rejected for prohibited content, and the number of incident questions that require a capability outside exception tracking. Do not invent a target percentage before seeing the workload. A checkout flow with queues and several downstream services will cross the tracing boundary sooner than a small catalog API. Also test operational exits. Can the team perform its required data-subject deletion and export procedure? Can it detect a job that never emits an exception? Can an on-call engineer receive the required notification without maintaining a custom bridge? One “no” may outweigh excellent grouping. The practical decision is pleasantly narrow: use simple exception tracking when a minimal envelope reliably reconstructs the incident. Move to deeper observability when the missing evidence is structural rather than another field. Keep the eval in CI either way. It makes future vendor comparisons about observable outcomes instead of feature-page impressions.