Skip to main content
The @effect/platform-browser package provides browser-specific implementations of Effect’s platform abstractions, enabling you to build client-side applications with HTTP clients, WebSockets, Web Workers, and browser APIs.

Installation

npm install @effect/platform-browser effect
This package is designed for use in web browsers and requires a bundler like Vite, Webpack, or esbuild.

When to Use

Use @effect/platform-browser when:
  • Building client-side web applications
  • You need to make HTTP requests from the browser
  • You want to work with WebSockets or Web Workers
  • You need access to browser APIs (geolocation, clipboard, permissions, etc.)
  • Building Progressive Web Apps (PWAs)

Core Features

Runtime

The BrowserRuntime module provides the entry point for running Effect programs in the browser:
import { BrowserRuntime } from "@effect/platform-browser"
import { Effect } from "effect"

const program = Effect.gen(function* () {
  yield* Effect.log("Hello from Browser!")
  return "success"
})

BrowserRuntime.runMain(program)
Features:
  • Handles page unload events (cleanup on navigation)
  • Automatic error handling
  • Integrates with browser lifecycle

HTTP Client

Make HTTP requests using the BrowserHttpClient module (built on fetch API):
import { BrowserHttpClient } from "@effect/platform-browser"
import { Effect } from "effect"
import { HttpClient, HttpClientRequest } from "effect/unstable/http"

const program = Effect.gen(function* () {
  const client = yield* HttpClient.HttpClient
  const response = yield* client.get("https://api.example.com/data")
  const data = yield* response.json
  return data
}).pipe(Effect.provide(BrowserHttpClient.layer))

BrowserRuntime.runMain(program)
Features:
  • Uses native fetch API
  • Automatic CORS handling
  • Supports all HTTP methods
  • Handles request/response transformations

WebSockets

Connect to WebSocket servers using the BrowserSocket module:
import { BrowserSocket } from "@effect/platform-browser"
import { Effect, Stream } from "effect"
import { Socket } from "effect/unstable/socket"

const program = Effect.gen(function* () {
  const socket = yield* BrowserSocket.make("wss://example.com/ws")
  
  // Send a message
  yield* socket.write("Hello Server!")
  
  // Listen for messages
  yield* socket.run.pipe(
    Stream.tap((message) => Effect.log(`Received: ${message}`)),
    Stream.take(10),
    Stream.runDrain
  )
}).pipe(Effect.scoped)

BrowserRuntime.runMain(program)

Web Workers

Manage Web Workers with the BrowserWorker module:
import { BrowserWorker } from "@effect/platform-browser"
import { Effect } from "effect"
import { Worker } from "effect/unstable/platform"

const program = Effect.gen(function* () {
  const worker = yield* Worker.Worker
  
  // Send work to the worker
  const result = yield* worker.execute({
    task: "process",
    data: [1, 2, 3, 4, 5]
  })
  
  yield* Effect.log(`Worker result: ${result}`)
}).pipe(Effect.provide(BrowserWorker.layer))

BrowserRuntime.runMain(program)

Key-Value Storage

Use browser storage (localStorage/sessionStorage) with the BrowserKeyValueStore module:
import { BrowserKeyValueStore } from "@effect/platform-browser"
import { Effect } from "effect"
import { KeyValueStore } from "effect/unstable/platform"

const program = Effect.gen(function* () {
  const store = yield* KeyValueStore.KeyValueStore
  
  // Save data
  yield* store.set("user", { id: 1, name: "Alice" })
  
  // Retrieve data
  const user = yield* store.get("user")
  yield* Effect.log(`User: ${JSON.stringify(user)}`)
  
  // Remove data
  yield* store.remove("user")
}).pipe(Effect.provide(BrowserKeyValueStore.layerLocal))

BrowserRuntime.runMain(program)
Supports both localStorage and sessionStorage:
// Use localStorage (persistent)
Effect.provide(BrowserKeyValueStore.layerLocal)

// Use sessionStorage (per-session)
Effect.provide(BrowserKeyValueStore.layerSession)

Browser APIs

Geolocation

Access device location with the Geolocation module:
import { Geolocation } from "@effect/platform-browser"
import { Effect } from "effect"

const program = Effect.gen(function* () {
  const geo = yield* Geolocation.Geolocation
  
  // Get current position
  const position = yield* geo.getCurrentPosition()
  yield* Effect.log(`Lat: ${position.coords.latitude}`)  
  yield* Effect.log(`Lng: ${position.coords.longitude}`)
  
  // Watch position changes
  yield* geo.watchPosition().pipe(
    Stream.tap((pos) => Effect.log(`Moving to: ${pos.coords.latitude}`))
  )
}).pipe(Effect.provide(Geolocation.layer))

BrowserRuntime.runMain(program)

Clipboard

Interact with the clipboard using the Clipboard module:
import { Clipboard } from "@effect/platform-browser"
import { Effect } from "effect"

const program = Effect.gen(function* () {
  const clipboard = yield* Clipboard.Clipboard
  
  // Write text to clipboard
  yield* clipboard.writeText("Hello, Clipboard!")
  
  // Read text from clipboard
  const text = yield* clipboard.readText()
  yield* Effect.log(`Clipboard: ${text}`)
}).pipe(Effect.provide(Clipboard.layer))

BrowserRuntime.runMain(program)

Permissions

Check and request browser permissions with the Permissions module:
import { Permissions } from "@effect/platform-browser"
import { Effect } from "effect"

const program = Effect.gen(function* () {
  const permissions = yield* Permissions.Permissions
  
  // Check permission status
  const status = yield* permissions.query({ name: "geolocation" })
  yield* Effect.log(`Geolocation permission: ${status.state}`)
  
  // Request permission (if needed)
  if (status.state === "prompt") {
    const result = yield* permissions.request({ name: "geolocation" })
    yield* Effect.log(`Permission ${result.state}`)
  }
}).pipe(Effect.provide(Permissions.layer))

BrowserRuntime.runMain(program)

Available Modules

ModuleDescription
BrowserRuntimeRun Effect programs in the browser
BrowserHttpClientMake HTTP requests (fetch-based)
BrowserSocketWebSocket client
BrowserWorkerWeb Worker management
BrowserWorkerRunnerWorker runner for parallel processing
BrowserKeyValueStorelocalStorage/sessionStorage access
BrowserStreamBrowser stream integration
GeolocationAccess device location
ClipboardRead/write clipboard
PermissionsCheck and request permissions

Streams and Reactive Programming

The browser package integrates well with Effect’s Stream module:
import { BrowserSocket } from "@effect/platform-browser"
import { Effect, Stream } from "effect"

const program = Effect.gen(function* () {
  const socket = yield* BrowserSocket.make("wss://example.com/ws")
  
  // Process incoming messages reactively
  yield* socket.run.pipe(
    Stream.map((msg) => JSON.parse(msg)),
    Stream.filter((data) => data.type === "update"),
    Stream.tap((data) => Effect.log(`Update: ${data.value}`)),
    Stream.runDrain
  )
}).pipe(Effect.scoped)

Integration with UI Frameworks

You can integrate Effect with React, Vue, or other frameworks:
import { BrowserRuntime, BrowserHttpClient } from "@effect/platform-browser"
import { Effect } from "effect"
import { HttpClient } from "effect/unstable/http"
import { useState, useEffect } from "react"

function UserProfile() {
  const [user, setUser] = useState(null)
  
  useEffect(() => {
    const program = Effect.gen(function* () {
      const client = yield* HttpClient.HttpClient
      const response = yield* client.get("/api/user")
      return yield* response.json
    }).pipe(Effect.provide(BrowserHttpClient.layer))
    
    BrowserRuntime.runPromise(program).then(setUser)
  }, [])
  
  return <div>{user?.name}</div>
}

Error Handling

Handle browser-specific errors gracefully:
import { BrowserHttpClient } from "@effect/platform-browser"
import { Effect } from "effect"
import { HttpClient, HttpClientError } from "effect/unstable/http"

const program = Effect.gen(function* () {
  const client = yield* HttpClient.HttpClient
  const response = yield* client.get("https://api.example.com/data")
  return yield* response.json
}).pipe(
  Effect.catchTag("ResponseError", (error) =>
    Effect.gen(function* () {
      yield* Effect.log(`HTTP Error: ${error.response.status}`)
      return { fallback: true }
    })
  ),
  Effect.catchTag("RequestError", (error) =>
    Effect.gen(function* () {
      yield* Effect.log("Network error, check connection")
      return { offline: true }
    })
  ),
  Effect.provide(BrowserHttpClient.layer)
)

Dependencies

The package has minimal external dependencies:
  • multipasta: Multipart form data handling
Most functionality is built on native browser APIs.

Build docs developers (and LLMs) love