Skip to content

gRPC-Web — Complete Guide

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about grpc. We cover key concepts, practical examples, and best practices to help you master this topic.

gRPC-Web enables browser applications to call gRPC services. Unlike native gRPC, gRPC-Web works through HTTP/1.1 or HTTP/2 and requires a proxy. This lesson covers setup, client usage, and limitations.

What You'll Learn

  • How gRPC-Web differs from native gRPC
  • How to set up an Envoy proxy for gRPC-Web
  • How to use the gRPC-Web JavaScript client
  • How to handle streaming limitations
  • Production deployment considerations

Why It Matters

Modern web applications increasingly use gRPC for backend services. gRPC-Web bridges the gap between browser clients and gRPC backends, enabling efficient API communication without REST wrappers.

Real-World Use

A SaaS platform uses gRPC-Web to power its React-based dashboard. When users view analytics, the browser directly calls gRPC services through Envoy, reducing latency by 40% compared to the previous REST-based approach.

Flow Chart

flowchart LR
    A[Browser] -->|HTTP/1.1| B[Envoy Proxy]
    B -->|HTTP/2| C[gRPC Server]
    C --> D{Response}
    D -->|Unary| E[JSON/Binary]
    D -->|Stream| F[Chunked Response]
    E --> B
    F --> B
    B --> A

Code Examples

Example 1: Envoy Proxy Configuration for gRPC-Web

static_resources:
  listeners:
  - name: web_listener
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 8080
    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: grpc_web
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: grpc_backend
          http_filters:
          - name: envoy.filters.http.grpc_web
          - name: envoy.filters.http.router
  clusters:
  - name: grpc_backend
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    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_backend
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: localhost
                port_value: 50051

Expected output: Envoy listens on port 8080, translates gRPC-Web requests to native gRPC, and proxies to the backend on port 50051.

Example 2: gRPC-Web Client in JavaScript

import { HelloRequest, HelloReply } from './helloworld_pb.js';
import { GreeterClient } from './helloworld_grpc_web_pb.js';

const client = new GreeterClient(
  'http://localhost:8080');

const request = new HelloRequest();
request.setName('Alice');

client.sayHello(request, {},
  (err, response) => {
    if (err) {
      console.error('Error:', err.message);
      return;
    }
    console.log('Response:',
      response.getMessage());
  });

// Output: Response: Hello Alice

Expected output: Browser sends gRPC-Web request to Envoy and receives the greeting response.

Example 3: gRPC-Web with TypeScript and Async/Await

import { GreeterClient } from './helloworld_grpc_web_pb';
import { HelloRequest } from './helloworld_pb';

async function greet(name: string): Promise<string> {
  const client = new GreeterClient(
    'http://localhost:8080',
    null, null);

  return new Promise((resolve, reject) => {
    const request = new HelloRequest();
    request.setName(name);

    client.sayHello(request, {},
      (error: grpcWeb.Error, response: HelloReply) => {
        if (error) {
          reject(new Error(error.message));
        } else {
          resolve(response.getMessage());
        }
      });
  });
}

greet('Bob').then(console.log);
// Output: Hello Bob

Expected output: TypeScript client calls gRPC service through Envoy proxy and logs the response.

Common Mistakes

Mistake Explanation
Expecting full streaming support gRPC-Web supports limited streaming; server-side streaming works but client-side streaming requires special handling
Bypassing the proxy Browsers cannot call gRPC directly; a proxy like Envoy is always required
Using native gRPC libraries in browser Native gRPC uses HTTP/2 and gRPC-specific features not available in browsers
Forgetting CORS configuration Envoy needs CORS headers configured for browser-based gRPC-Web calls
Not handling binary protobuf gRPC-Web uses binary format; ensure your application can deserialize protobuf messages
Ignoring performance implications Protobuf Serialization in JavaScript can be CPU-intensive for large messages

Practice Questions

  1. Why does gRPC-Web require a proxy?
  2. What streaming types are supported in gRPC-Web?
  3. How does gRPC-Web handle binary data in browsers?
  4. What are the performance differences between gRPC and gRPC-Web?
  5. How do you handle authentication in gRPC-Web?

Challenge

Build a full-stack application with a React frontend using gRPC-Web, an Envoy proxy, and a Go gRPC backend. Implement a real-time chat feature using server-side streaming through gRPC-Web.

FAQ

Does gRPC-Web support all gRPC features?

No, gRPC-Web has limitations: no client-side streaming, no bidirectional streaming, and limited trailer support compared to native gRPC.

Can I use gRPC-Web without Envoy?

While Envoy is the most common proxy, alternatives include gRPC-Web Go Proxy, Traefik, and NGINX (with gRPC-Web module).

Does gRPC-Web work with all browsers?

Yes, gRPC-Web works with all modern browsers that support fetch or XHR, including Chrome, Firefox, Safari, and Edge.

How do I handle errors in gRPC-Web?

gRPC-Web errors are translated to HTTP status codes and can be caught in the client callback or promise rejection handler.

Is gRPC-Web suitable for production?

Yes, gRPC-Web is production-ready and used by companies like Square, Netflix, and Cockroach Labs for their web interfaces.

How does gRPC-Web handle protobuf message sizes?

gRPC-Web has the same message size limits as gRPC (default 4MB). Large messages can cause browser performance issues.

Mini Project

Build a gRPC-Web application that displays real-time stock prices. Use a Go gRPC server with server-side streaming, an Envoy proxy for gRPC-Web translation, and a React frontend that subscribes to stock price updates and renders them in a dashboard.

What's Next

Build a complete gRPC project applying all concepts

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro