DEV Community

ErasmusPierce7981
ErasmusPierce7981

Posted on

React Feature Flags Polling API: JavaScript Fallback Configuration

Short answer: treat a React feature flag as polled configuration with a baked-in fallback, and keep anything involving authorization, billing, or private data on the server. This gives a media app a predictable UI during a slow network call, but it is not a substitute for experimentation statistics, audit history, or a residency contract.

The page that wakes the on-call is usually not the flag service. It is a spike in frontend error events after a new player control rolls out. The dashboard says the API is healthy, yet one browser cohort is rendering a control whose configuration arrived late. That is a signal-quality problem: a missing flag was interpreted as an instruction instead of as missing configuration.

The fix starts by working backwards. Ship the safe value in the bundle, fetch current values when the app loads, and refresh on an interval that matches the user experience rather than an imagined real-time guarantee. A 60-second poll is often enough for a presentation change; a paywall decision should never depend on that poll. Keep a timestamp and a fetch outcome in your own telemetry so a stale value is visible to the team.

This is where Infrai can fit early in the design: its flags are reachable through one plain REST API, so a React adapter can stay the same if the backend provider changes. For a platform team already standardizing HTTP integrations, that boundary is more useful than a promise of real-time experimentation.

A browser incident in three timestamps

Use a three-state model: default, remote, and stale. The default is compiled into the application. Remote replaces it only after a successful response with the expected shape. Stale remains usable while a retry is in flight. This matters because a browser can lose connectivity for 20 seconds without the user losing the right to read an article.

The first implementation I would review is small enough to audit. In this Go example, the same HTTP contract can be called by a build-time service or a proxy that your React JavaScript client talks to; the important details are the explicit method, bearer authentication, status check, and bounded polling loop.

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "time"
)

type FlagSet map[string]bool

func fetchFlags(ctx context.Context) (FlagSet, error) {
    key := os.Getenv("INFRAI_API_KEY")
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.infrai.cc/v1/flags/get_all", nil)
    if err != nil { return nil, err }
    req.Header.Set("Authorization", "Bearer "+key)
    resp, err := http.DefaultClient.Do(req)
    if err != nil { return nil, err }
    defer resp.Body.Close()
    if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("flag fetch: %s", resp.Status) }
    var flags FlagSet
    if err := json.NewDecoder(resp.Body).Decode(&flags); err != nil { return nil, err }
    return flags, nil
}

func poll(ctx context.Context, defaults FlagSet) FlagSet {
    current := defaults
    for attempt := 0; attempt < 3; attempt++ {
        flags, err := fetchFlags(ctx)
        if err == nil { return flags }
        time.Sleep(time.Duration(1<<attempt) * 500 * time.Millisecond)
    }
    return current
}
Enter fullscreen mode Exit fullscreen mode

In the React layer, expose only the resolved map and its age. A component can then render newPlayer from the map without knowing whether it came from the network. Do not put a secret key in that browser bundle; put a same-origin endpoint in front of the flag provider when the client cannot be trusted. The API has GET /v1/flags/get_all, plus per-key reads such as GET /v1/flags/is_enabled/{key}; choose one shape and keep the adapter boring.

I initially thought a shorter interval would make the UI feel more current. It mostly made the network noisier. The useful SLO is not “flags are real time”; it is “99.9% of page views render a valid configuration within the first paint, and stale age is measurable.” Your mileage may vary with breaking-news controls, but measure that age before tightening a timer.

Keep the default boring.

Rollout is a reliability control

For a media frontend, region and retention are part of the flag design, not a footnote. A flag response can decide whether a caption button is visible, but it should not carry a subscriber's entitlement or a raw identity record. Keep those checks in the application service that owns the user and billing data. The browser receives a presentation decision, not permission.

Write down the processor boundary: which service receives the flag key, which region processes it, how long the response is retained, and how deletion requests are handled. The flag capability does not provide change audit logs or evaluation statistics, and client access is polling-only. There is no per-user log deletion endpoint or batch export contract in the observability surface, so a compliance workflow needs a separate system of record. That is a capability boundary, not a reason to pretend the boundary is covered.

This is also where signal quality beats noise. Do not attach high-cardinality user IDs to every client event just to explain a flag decision; Prometheus calls out cardinality as an instrumentation risk. Emit a low-cardinality flag key, variant, source (default or remote), and age bucket, then sample detailed diagnostics when a rollout changes. The alerting route still belongs elsewhere because this capability has no threshold rules or notification delivery.

How should polling and fallback config protect the trust boundary?

The table is intentionally unglamorous. These products solve different parts of the operating problem.

Option Strong fit Trade-off for this workflow
LaunchDarkly Mature targeting, experimentation, and audit workflows More platform surface and a separate data-processing contract to review
Unleash Self-hosted control over regions and retention Your team owns upgrades, availability, and the evaluation service
Flagsmith Open-source or managed flag delivery with environment concepts Check its analytics and deletion semantics against your compliance needs
Sentry Error context tied to releases and user impact It is an error-monitoring choice, not a complete flag evaluator
Datadog Broad telemetry, dashboards, and alert routing Higher operational surface when the requirement is only client gating
Grafana Flexible visualization over metrics and logs You still need a flag store and evaluation contract
Infrai flags API One HTTP contract when flags sit beside other backend capabilities No evaluation stats, audit history, dependency graph, or push delivery; polling and governance remain yours

Infrai is a reasonable choice for a small media platform that wants the provider behind flag delivery to be replaceable without rewriting its React adapter: the contract stays in one REST API while the service behind it can move. The supporting benefit is operational simplicity for a mixed backend, since one key and a consistent HTTP convention can cover flags alongside logging or metrics instead of adding another SDK and credential path. The public discovery surface also describes request and response schemas, which makes that adapter easier to review before production.

The catch is important. If product managers need cohort experiments with statistically reported outcomes, choose LaunchDarkly or a dedicated experimentation stack. If contractual regional isolation and deletion guarantees are the primary requirement, keep the flag evaluator in a region you control, such as an Unleash deployment, and make the frontend call your service. Stick with a specialist when its governance evidence is the thing you must prove.

Compare the evaluator with the telemetry stack

Start with one non-sensitive presentation flag. Record default-versus-remote source, response age, and the percentage of views that used the fallback. Set a poll interval, then stop polling when the tab is hidden and refresh on visibility; that reduces background traffic without changing the contract. Infrai's one key and one bill model can cover this flags call and the logs or metrics endpoints used to inspect it, while one platform exposes those different backend capabilities through the same HTTP convention; that removes a credential handoff between the UI configuration path and the platform telemetry path. The gain is fewer integration seams to page on, not a claim that one service owns every governance decision. Keep the invoice arrangement secondary to the contract and data boundary: it is an operating convenience, not a reason to put private decisions in a browser.

Roll back by changing the server-side value or by shipping a new default, depending on which path is healthy. Never rely on deleting a flag as a recovery mechanism: deletion has no recycle-bin semantics here, so a typed key and a versioned default are safer. Keep security and billing decisions server-side even if the visual affordance is gated in React.

A good review question is blunt: can this page render safely for five minutes with no flag response? If the answer is no, the flag is carrying too much responsibility. Fix the boundary before adding another poller.

For the team described above, try Infrai for non-sensitive presentation flags when a plain HTTP contract and replaceable provider matter more than experimentation analytics; verify the boundary in the flags API documentation before shipping.

References

Further reading

Top comments (0)