Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/get-convex/convex-backend/llms.txt

Use this file to discover all available pages before exploring further.

The browser module provides clients for accessing Convex from browser JavaScript applications without React.

Installation

npm install convex

Importing

import { ConvexClient, ConvexHttpClient } from "convex/browser";
If you are using React, use the convex/react module instead for better integration with React’s rendering and state management.

ConvexClient

A WebSocket-based client that subscribes to queries and executes mutations and actions. Provides reactive updates when query results change.

Basic usage

import { ConvexClient } from "convex/browser";
import { api } from "./convex/_generated/api";

const client = new ConvexClient("https://small-mouse-123.convex.cloud");

const unsubscribe = client.onUpdate(
  api.messages.list,
  {},
  (messages) => {
    console.log(messages);
  }
);

Constructor options

const client = new ConvexClient(address, {
  disabled: false,
  unsavedChangesWarning: true,
  // ... other options
});
Options:
  • disabled - Disables subscriptions (useful for SSR)
  • unsavedChangesWarning - Prompts users about unsaved changes before leaving

Subscribing to queries

The onUpdate method subscribes to a query and calls a callback when results change:
const unsubscribe = client.onUpdate(
  api.messages.list,
  { channel: "#general" },
  (messages) => {
    // Update UI with new messages
    renderMessages(messages);
  },
  (error) => {
    // Handle errors
    console.error("Query error:", error);
  }
);
Return value: The return value is both a function and an object:
// Use as a function
const unsubscribe = client.onUpdate(api.messages.list, {}, callback);
unsubscribe();

// Use as an object
const subscription = client.onUpdate(api.messages.list, {}, callback);
const current = subscription.getCurrentValue();
subscription.unsubscribe();

Executing mutations

const taskId = await client.mutation(api.tasks.create, {
  text: "New task"
});

Executing actions

const result = await client.action(api.ai.generateSummary, {
  text: "Some long text..."
});

One-time queries

const tasks = await client.query(api.tasks.list, { completed: false });

Authentication

Set authentication with an async token fetcher:
client.setAuth(
  async () => {
    const token = await getAuthToken();
    return token; // or null if unavailable
  },
  (isAuthenticated) => {
    console.log("Auth status:", isAuthenticated);
  }
);

Connection state

// Get current state
const state = client.connectionState();
console.log(state.isConnected);

// Subscribe to changes
const unsubscribe = client.subscribeToConnectionState((state) => {
  updateConnectionIndicator(state.isConnected);
});

Paginated queries (experimental)

const subscription = client.onPaginatedUpdate_experimental(
  api.messages.list,
  { channel: "#general" },
  { initialNumItems: 20 },
  (result) => {
    renderMessages(result.results);
    if (result.status === "CanLoadMore") {
      enableLoadMoreButton(() => result.loadMore(10));
    }
  }
);

Cleanup

Always close the client when done:
await client.close();

ConvexHttpClient

An HTTP-based client for executing queries, mutations, and actions without maintaining a WebSocket connection. Suitable for server-side code or applications that don’t need real-time updates.

Basic usage

import { ConvexHttpClient } from "convex/browser";
import { api } from "./convex/_generated/api";

const client = new ConvexHttpClient("https://small-mouse-123.convex.cloud");

const tasks = await client.query(api.tasks.list, {});

Constructor options

const client = new ConvexHttpClient(address, {
  skipConvexDeploymentUrlCheck: false,
  logger: true, // or false, or custom Logger
  auth: "eyJhbGciOi...", // Optional initial auth token
  fetch: customFetch // Optional custom fetch implementation
});

Executing queries

const tasks = await client.query(api.tasks.list, { completed: false });

Executing mutations

Mutations are queued by default to ensure ordered execution:
// Queued mutation (default)
const taskId = await client.mutation(api.tasks.create, {
  text: "New task"
});

// Skip the queue for parallel execution
await client.mutation(
  api.tasks.create,
  { text: "Another task" },
  { skipQueue: true }
);

Executing actions

const result = await client.action(api.ai.generateSummary, {
  text: "Some long text..."
});

Authentication

// Set auth token
client.setAuth("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...");

// Clear auth
client.clearAuth();

Consistent queries (experimental)

Execute multiple queries at the same timestamp:
const client = new ConvexHttpClient(address);

const tasks = await client.consistentQuery(api.tasks.list, {});
const users = await client.consistentQuery(api.users.list, {});
// Both queries see the database at the same point in time
Consistent queries have a 30-second time limit. Create a new client for a fresh timestamp.

Choosing a client

ClientUse caseConnectionReactivity
ConvexClientBrowser appsWebSocketYes
ConvexHttpClientServerless functions, non-reactive appsHTTPNo
ConvexReactClientReact appsWebSocketYes
Use ConvexClient when:
  • Building a browser application without React
  • You need real-time updates
  • You want to subscribe to query changes
Use ConvexHttpClient when:
  • Running in serverless functions or edge workers
  • Making one-off requests
  • You don’t need real-time updates
  • Minimizing connection overhead is important

Error handling

import { ConvexError } from "convex/values";

try {
  await client.mutation(api.tasks.create, { text: "New task" });
} catch (error) {
  if (error instanceof ConvexError) {
    // Handle application errors with data
    console.error("Convex error:", error.data);
  } else {
    // Handle network or other errors
    console.error("Error:", error);
  }
}

Type safety

All clients use generated TypeScript types:
import { api } from "./convex/_generated/api";

// Fully type-safe
const tasks = await client.query(api.tasks.list, {
  completed: false // Type-checked argument
});
// tasks has the correct return type

BaseConvexClient

For advanced use cases, you can extend BaseConvexClient to build custom clients:
import { BaseConvexClient } from "convex/browser";

const client = new BaseConvexClient(
  address,
  (updatedQueries) => {
    // Handle query updates
  },
  options
);

Best practices

  • Store deployment URLs in environment variables
  • Always close clients when done to prevent memory leaks
  • Use ConvexClient for browser apps that need reactivity
  • Use ConvexHttpClient for server-side code
  • Handle errors appropriately for mutations and actions
  • For React applications, use convex/react instead
  • Implement connection state UI for better user experience