Browser Client
Use BrowserOCPPClient in browser environments — React, Vue, Next.js, and more.
BrowserOCPPClient is a lightweight OCPP WebSocket RPC client designed for browser environments. It enables building charge point simulators, testing dashboards, and debugging tools directly in the browser — using the same typed API as OCPPClient.
import { BrowserOCPPClient } from "ocpp-ws-io/browser";[!IMPORTANT] The browser client is designed for testing and simulating charge points — it does not support all OCPP features. Missing: Security Profiles (0–3), Strict Mode (schema validation), TLS/mTLS configuration, WebSocket Ping/Pong, and custom HTTP headers. For production charge point communication, use
OCPPClientin a Node.js environment.
Limitations vs OCPPClient
OCPPClient depends on Node.js modules (ws, node:crypto, node:events, node:net) — it can't run in the browser. BrowserOCPPClient replaces these with browser-native APIs, but this comes with trade-offs:
| Feature | OCPPClient | BrowserOCPPClient |
|---|---|---|
| WebSocket | ws (Node.js) | Native browser WebSocket |
| Events | node:events | Custom lightweight EventEmitter |
| ID Generation | @paralleldrive/cuid2 | @paralleldrive/cuid2 |
| Security Profiles | 0–3 (TLS, mTLS, certs) | N/A (handled by browser/TLS) |
| Custom Headers | ✅ via ws | ❌ browser limitation |
| Ping/Pong | ✅ | ❌ browser limitation |
| Type Safety | ✅ Full | ✅ Full (same generated types) |
| Reconnection | ✅ | ✅ |
| Strict Mode | ✅ | ❌ |
Quick Start
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
const client = new BrowserOCPPClient({
endpoint: "wss://csms.example.com/ocpp",
identity: "CP001",
protocols: ["ocpp1.6"],
});
// Register a handler — params are auto-typed for OCPP 1.6 Reset
client.handle("Reset", ({ params }) => {
console.log("Reset type:", params.type);
return { status: "Accepted" };
});
// Connect and send a BootNotification
await client.connect();
const response = await client.call("ocpp1.6", "BootNotification", {
chargePointVendor: "VendorX",
chargePointModel: "ModelY",
});
console.log("Status:", response.status); // typed: "Accepted" | "Pending" | "Rejected"Configuration
const client = new BrowserOCPPClient(options: BrowserClientOptions);BrowserClientOptions
| Option | Type | Default | Description |
|---|---|---|---|
identity | string | required | Charging station ID |
endpoint | string | required | WebSocket URL (ws:// or wss://) |
protocols | string[] | [] | OCPP subprotocols to negotiate |
query | Record<string, string> | — | Additional URL query parameters |
reconnect | boolean | true | Auto-reconnect on disconnect |
maxReconnects | number | Infinity | Max reconnection attempts |
backoffMin | number | 1000 | Initial reconnect delay (ms) |
backoffMax | number | 30000 | Maximum reconnect delay (ms) |
callTimeoutMs | number | 30000 | Default RPC call timeout (ms) |
callConcurrency | number | 1 | Max concurrent outbound calls |
maxBadMessages | number | Infinity | Close after N consecutive bad messages |
respondWithDetailedErrors | boolean | false | Include error details in RPC error responses |
Connection Lifecycle
Connection States
BrowserOCPPClient.CONNECTING; // 0
BrowserOCPPClient.OPEN; // 1
BrowserOCPPClient.CLOSING; // 2
BrowserOCPPClient.CLOSED; // 3
// Check current state
if (client.state === BrowserOCPPClient.OPEN) {
await client.call("Heartbeat", {});
}Properties
| Property | Type | Description |
|---|---|---|
client.identity | string | Charging station identity |
client.protocol | string | undefined | Negotiated OCPP subprotocol |
client.state | ConnectionState | Current connection state |
Making Calls
// Version-aware call — fully typed params and response
const result = await client.call("ocpp1.6", "BootNotification", {
chargePointVendor: "VendorX",
chargePointModel: "ModelY",
});
result.status; // typed: "Accepted" | "Pending" | "Rejected"
// OCPP 2.0.1 — different shape, still fully typed
const result201 = await client.call("ocpp2.0.1", "BootNotification", {
chargingStation: { model: "ModelX", vendorName: "VendorY" },
reason: "PowerUp",
});
// Default protocol call (uses the client's type parameter P)
const res = await client.call("Heartbeat", {});
// Explicit response type (for custom/vendor methods)
const custom = await client.call<{ result: string }>("VendorAction", {
data: "hello",
});Call Options
// Timeout
const res = await client.call(
"Reset",
{ type: "Soft" },
{
timeoutMs: 5000,
},
);
// AbortSignal
const controller = new AbortController();
const res2 = await client.call(
"Heartbeat",
{},
{
signal: controller.signal,
},
);
// Cancel the call
controller.abort();Handling Incoming Calls
Register handlers for incoming server-to-client calls. The API is identical to OCPPClient.handle().
// Version-specific handler — only triggers for ocpp1.6
client.handle("ocpp1.6", "Reset", ({ params }) => {
params.type; // typed: "Hard" | "Soft" (OCPP 1.6 shape)
return { status: "Accepted" };
});
// Generic handler — triggers for any negotiated protocol
client.handle("Reset", ({ params, protocol }) => {
console.log(`Reset via ${protocol}:`, params.type);
return { status: "Accepted" };
});
// Wildcard handler — catches all unhandled methods
client.handle((method, { params }) => {
console.log(`Unhandled method: ${method}`);
return {};
});Handler Priority
When a call arrives, handlers are checked in this order:
- Version-specific handler (e.g.,
"ocpp1.6:Reset") - Generic handler (e.g.,
"Reset") - Wildcard handler
NOREPLY
Return NOREPLY from a handler to suppress the automatic response:
import { NOREPLY } from "ocpp-ws-io/browser";
client.handle("StatusNotification", ({ params }) => {
// Process but don't send a response
return NOREPLY;
});Removing Handlers
client.removeHandler("Reset"); // remove generic
client.removeHandler("ocpp1.6", "Reset"); // remove version-specific
client.removeHandler(); // remove wildcard
client.removeAllHandlers(); // remove allEvents
client.on("open", (event) => {
/* WebSocket connected */
});
client.on("close", ({ code, reason }) => {
/* WebSocket disconnected */
});
client.on("error", (error) => {
/* Connection or WebSocket error */
});
client.on("connecting", ({ url }) => {
/* Attempting connection */
});
client.on("reconnect", ({ attempt, delay }) => {
/* Scheduled reconnection */
});
client.on("message", (message) => {
/* Any parsed OCPP message */
});
client.on("call", (call) => {
/* Incoming OCPP Call */
});
client.on("callResult", (result) => {
/* Received CallResult */
});
client.on("callError", (error) => {
/* Received CallError */
});
client.on("badMessage", ({ message, error }) => {
/* Malformed message received */
});Reconnection
BrowserOCPPClient supports automatic reconnection with exponential backoff, identical to OCPPClient:
const client = new BrowserOCPPClient({
identity: "CP001",
endpoint: "wss://csms.example.com/ocpp",
protocols: ["ocpp1.6"],
reconnect: true, // default: true
maxReconnects: 10, // default: Infinity
backoffMin: 1000, // default: 1000ms
backoffMax: 30000, // default: 30000ms
});
client.on("reconnect", ({ attempt, delay }) => {
console.log(`Reconnect attempt ${attempt} in ${delay}ms`);
});
client.on("close", ({ code, reason }) => {
console.log(`Disconnected: ${code} ${reason}`);
});Toggle Reconnection at Runtime
// Disable reconnection
client.reconfigure({ reconnect: false });
// Re-enable with different settings
client.reconfigure({
reconnect: true,
maxReconnects: 5,
backoffMin: 2000,
});Closing the Connection
// Graceful close (waits for pending calls)
await client.close();
// Custom close code and reason
await client.close({ code: 1000, reason: "User navigated away" });
// Force close (immediately terminates)
await client.close({ force: true });
// Wait for in-flight calls to complete first
await client.close({ awaitPending: true });Framework Integration
React
import { useEffect, useRef, useState } from "react";
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
function useOCPP(identity: string, endpoint: string) {
const clientRef = useRef<BrowserOCPPClient | null>(null);
const [connected, setConnected] = useState(false);
useEffect(() => {
const client = new BrowserOCPPClient({
identity,
endpoint,
protocols: ["ocpp1.6"],
});
client.on("open", () => setConnected(true));
client.on("close", () => setConnected(false));
client.connect();
clientRef.current = client;
return () => { client.close(); };
}, [identity, endpoint]);
return { client: clientRef.current, connected };
}
// Usage
function ChargingStation() {
const { client, connected } = useOCPP("CP001", "wss://csms.example.com/ocpp");
const sendBoot = async () => {
if (!client) return;
const res = await client.call("BootNotification", {
chargePointVendor: "VendorX",
chargePointModel: "ModelY",
});
console.log("Boot:", res.status);
};
return (
<div>
<p>Status: {connected ? "Connected" : "Disconnected"}</p>
<button onClick={sendBoot} disabled={!connected}>Send Boot</button>
</div>
);
}Next.js (Client Component)
"use client";
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
// ✅ Works in client components — no Node.js dependencies
const client = new BrowserOCPPClient({
identity: "CP001",
endpoint: "wss://csms.example.com/ocpp",
protocols: ["ocpp1.6"],
});Note:
OCPPClientfrom"ocpp-ws-io"cannot be imported in client components — it requires Node.js modules. UseBrowserOCPPClientfrom"ocpp-ws-io/browser"instead.
Vue
import { ref, onMounted, onUnmounted } from "vue";
import { BrowserOCPPClient } from "ocpp-ws-io/browser";
export function useOCPP(identity: string, endpoint: string) {
const client = ref<BrowserOCPPClient | null>(null);
const connected = ref(false);
onMounted(() => {
const c = new BrowserOCPPClient({
identity,
endpoint,
protocols: ["ocpp1.6"],
});
c.on("open", () => (connected.value = true));
c.on("close", () => (connected.value = false));
c.connect();
client.value = c;
});
onUnmounted(() => {
client.value?.close();
});
return { client, connected };
}Browser Exports
All exports available from the ocpp-ws-io/browser subpath:
import {
// Client
BrowserOCPPClient,
// Error classes
RPCGenericError,
RPCNotImplementedError,
RPCNotSupportedError,
RPCInternalError,
RPCProtocolError,
RPCSecurityError,
RPCFormatViolationError,
RPCFormationViolationError,
RPCPropertyConstraintViolationError,
RPCOccurrenceConstraintViolationError,
RPCTypeConstraintViolationError,
RPCMessageTypeNotSupportedError,
RPCFrameworkError,
TimeoutError,
// Utilities
createRPCError,
getErrorPlainObject,
// Constants
ConnectionState,
MessageType,
NOREPLY,
} from "ocpp-ws-io/browser";All types from the main package (OCPPProtocol, AllMethodNames, OCPPRequestType, OCPPResponseType, etc.) are re-exported for full type safety.