Home  /  Protocols  /  CDN gRPC-Web Proxy Guide
Protocols

CDN gRPC-Web Proxy: Binary Protocol Translation at Edge

By James Thornton, CDN Solutions ArchitectSep 7, 20269 min read

gRPC is efficient inside your data center, but it breaks at the browser edge. Browsers cannot speak native gRPC. A CDN gRPC-Web proxy solves this by translating between the browser's limited HTTP stack and your origin's binary HTTP/2 gRPC service — without sacrificing streaming, flow control, or protobuf efficiency.

TL;DR: Deploy gRPC-Web translation at the CDN edge to terminate browser HTTP/1.1, re-frame to HTTP/2 gRPC with trailers, and multiplex to origin over persistent connections. This cuts connection overhead by 60-80% and enables streaming to the browser without a dedicated gateway fleet.

Why gRPC Needs Translation at the Edge

Native gRPC relies on HTTP/2 features that the Fetch API and XMLHttpRequest do not expose: trailing headers (trailers), full control over binary framing, and bidirectional streaming. The gRPC-Web protocol is a deliberate adaptation that encodes the same protobuf payloads over HTTP/1.1 or HTTP/2 in a way browsers can handle.

Without an edge proxy, you have two bad options: expose a REST gateway that re-serializes to JSON (losing 30-40% payload efficiency) or run a self-managed Envoy fleet just for translation. A CDN edge proxy eliminates both by handling translation within PoPs, close to users. For background on how PoPs handle protocol termination, see our CDN architecture overview and edge computing guide.

gRPC vs gRPC-Web vs REST at the Edge

FeatureNative gRPCgRPC-Web (via CDN Proxy)REST / JSON
TransportHTTP/2 only, trailers requiredHTTP/1.1 or HTTP/2, no trailers needed in browserHTTP/1.1 or HTTP/2
PayloadProtobuf binary, 5-byte frame headerSame protobuf binary + gRPC-Web framingJSON text, 2-4x larger
StreamingFull bidi streamingServer streaming + unary (bidi via websockets)Server-sent events / polling
Browser SupportNoneAll modern browsersAll browsers
CDN CacheableNo (trailers break cache)Unary: Yes with custom keyYes, natively
Edge OverheadN/A1-5ms translationJSON serialization 5-15ms

How Edge Translation Works

The proxy performs three critical translations in the data path:

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages
  1. Protocol downgrade/upgrade: Accepts content-type: application/grpc-web+proto over HTTP/1.1 from the browser, then re-emits application/grpc over HTTP/2 to origin.
  2. Framing conversion: Strips the gRPC-Web 1-byte flag + 4-byte length prefix wrapper and re-adds standard gRPC length-prefixed messages, handling grpc-status and grpc-message trailers.
  3. Connection coalescing: Multiplexes thousands of browser HTTP/1.1 connections onto a small pool of warm HTTP/2 connections to origin, reducing TLS and TCP handshake cost.
CDN gRPC-Web Proxy Translation Flow Diagram showing browser connecting via HTTP/1.1 gRPC-Web to CDN edge proxy, which translates to HTTP/2 gRPC to origin. Browser fetch / gRPC-Web JS grpc-web+proto HTTP/1.1 1. gRPC-Web CDN Edge Proxy Binary Translation Framing • Trailers • h2 Pool CACHE WAF TLS 2. Native gRPC HTTP/2 + trailers Origin gRPC Go / Java / Rust Server application/grpc HTTP/2 No trailers • Text safe Translates 5-byte frames • Injects grpc-status Persistent h2 conn pool
Figure 1: Edge proxy terminates gRPC-Web over HTTP/1.1 and proxies native gRPC over HTTP/2 with trailer translation and connection pooling.

Binary Framing: What the Proxy Actually Rewrites

Both protocols use the same 5-byte frame: 1 byte compressed flag + 4 bytes big-endian message length + protobuf bytes. The difference is trailer handling.

gRPC-Web text mode base64-encodes frames for proxies that buffer binary. gRPC-Web proto mode sends raw binary and is preferred at the edge for lower CPU. The edge proxy must:

# gRPC-Web frame (browser -> edge) POST /com.example.SearchService/Search HTTP/1.1 content-type: application/grpc-web+proto x-grpc-web: 1 accept: application/grpc-web+proto # 5-byte prefix + protobuf payload 00 00 00 00 0A 0A 07 68 65 6C 6C 6F 2D77 6F 72 6C 64 # Edge -> Origin (translated) POST /com.example.SearchService/Search HTTP/2 content-type: application/grpc te: trailers grpc-encoding: identity # Same frame, but response will use HTTP/2 trailers: grpc-status: 0 grpc-message: OK

Configuring the Edge Proxy

Most teams use Envoy's grpc_web filter at the edge, or a CDN-native toggle. Below are production-ready patterns.

Option 1: Envoy at CDN Edge (Recommended for control)

# envoy.yaml - edge listener with grpc_web filter static_resources: listeners: - name: edge_listener address: { socket_address: { address: 0.0.0.0, port_value: 443 } } filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http http_filters: - name: envoy.filters.http.grpc_web - name: envoy.filters.http.cors - name: envoy.filters.http.router route_config: virtual_hosts: - name: grpc_service domains: ["api.example.com"] routes: - match: { prefix: "/com.example." } route: cluster: grpc_origin timeout: 30s retry_policy: retry_on: unavailable, reset num_retries: 2 clusters: - name: grpc_origin connect_timeout: 0.25s type: STRICT_DNS typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: { http2_protocol_options: {} } load_assignment: cluster_name: grpc_origin endpoints: [{lb_endpoints: [{endpoint: {address: {socket_address: {address: origin.internal, port_value: 50051}}}]}]

Option 2: CDN-Native (Cloudflare / Fastly / CloudFront)

Enable gRPC-Web in the dashboard and set origin protocol to h2c or h2. Ensure your origin speaks HTTP/2 without TLS termination mismatch. For CloudFront, put an ALB or NLB with HTTP/2 target group in front of your gRPC servers.

Client Example (grpc-web JS)

// npm install grpc-web google-protobuf import { SearchServiceClient } from './generated/SearchService_grpc_web_pb'; import { SearchRequest } from './generated/search_pb'; const client = new SearchServiceClient('https://api.example.com', null, null); const req = new SearchRequest(); req.setQuery('edge proxy'); req.setPageSize(20); // Unary call - automatically uses application/grpc-web+proto client.search(req, {'x-request-id': crypto.randomUUID()}, (err, res) => { if (err) console.error(err.code, err.message); else console.log(res.getResultsList()); }); // Server streaming - edge proxy translates to chunked HTTP/1.1 const stream = client.streamResults(req); stream.on('data', (chunk) => render(chunk)); stream.on('error', (e) => { if (e.code !== 0) retryWithBackoff(); }); stream.on('end', () => console.log('stream complete'));

Performance Tuning at the Edge

Translation is cheap, but misconfiguration is not. Apply these settings to keep p95 under 30ms:

Measure with CDN performance metrics and correlate with Core Web Vitals — gRPC-Web streaming improves INP by avoiding polling waterfalls, but unoptimized framing can regress LCP if the proxy buffers too aggressively.

Pro tip: Enable access_log with %GRPC_STATUS% and %RESPONSE_CODE_DETAILS% at the edge. A 200 HTTP with grpc-status:14 (unavailable) is invisible to standard CDN dashboards that only track HTTP status.

Security and Reliability

Binary protocols obscure payloads from traditional WAFs. Configure edge security explicitly:

When Not to Use gRPC-Web at the Edge

Avoid gRPC-Web if you need true bidirectional streaming from the browser (use WebSockets or Connect protocol instead), or if your payloads are already JSON and <500B (REST overhead is negligible). For edge caching of large unary responses, consider Connect's application/proto with GET support, which maps better to CDN cache keys.

Edge Checklist

Frequently Asked Questions

Why can't browsers call gRPC directly without a proxy?
Browsers don't expose HTTP/2 trailers or raw binary frame control through fetch/XHR, both required for gRPC. gRPC-Web encodes the same protobuf payloads over HTTP/1.1 with length-prefixed frames and moves trailer data into headers the browser can read. The edge proxy restores proper HTTP/2 trailers toward origin.
Does gRPC-Web proxying add significant latency?
No — translation is typically 1–5ms per request at the PoP. You gain back more by multiplexing browser connections onto warm HTTP/2 origin connections and terminating TLS at the edge. Keep the proxy and origin peered in the same region and monitor p95 with edge timing headers.
Should I use Envoy, NGINX, or CDN-native gRPC-Web support?
If your CDN offers native gRPC-Web translation, use it to eliminate operational overhead. Choose Envoy when you need fine-grained retry, timeout, and observability per RPC. NGINX works for simple unary workloads but lacks robust streaming and trailer fidelity.
Can gRPC-Web proxies cache responses?
Unary responses can be cached if they are idempotent and safe — create a cache key from the method name plus a hash of the protobuf request body. Set explicit cache-control and vary on authorization headers. Never cache server-streaming responses; buffer them instead.

References & Standards: RFC 7234 · HTTP/2 specification

External References