Logo of Lexmount
DocsTemplatesBlogHelp Center
GitHub
Logo of LexmountLexmount Browser

Get started

Lexmount Documentation
Console guide

Browser

Web Fetch

OverviewQuick Start
Common Errors

Web Search

OverviewQuick StartSearch API

Runtime

OverviewQuickstartCapabilitiesExamples

Help and billing

Capability FAQCloud Browser, Web Fetch and Web Search API Pricing
ChangelogContact support

Examples

Copyable JavaScript examples for public HTTP services, remote files, private HTTP, processes, TCP, and cloud browsers.

Each JavaScript block is a standalone task: paste it into the instance's Code tab and select Run. For remote examples, start the client, replace <client-id> with its full ID, and confirm the required permissions are applied on Clients. Relative file paths use the client's startup directory.

Publish a public HTTP service

export default {
  async fetch(request, _env, ctx) {
    const path = new URL(request.url).pathname;
    if (path === '/health') return new Response('ok\n');
    ctx.waitUntil(Promise.resolve().then(() => console.log('Handled', path)));
    return Response.json({ method: request.method, path });
  },
};

After running, select Visit in the instance list to open the public entry. Change its path to /health to see ok. The URL allows anonymous access; implement authentication in your handler if needed. Use the address provided by the console instead of deriving or hardcoding its domain.

env is a frozen empty object. ctx.waitUntil() registers work after a response, but stop, replacement, or timeout can interrupt it; completion is not guaranteed. The service runs until you stop it, replace the code, or reach the maximum runtime set in the console. This public entry and the client-local host.http.serve() below are separate service interfaces.

Cloud browser navigation, screenshots, and snapshots

No remote client is required. Browser calls use the task submission's project credentials and require browser entitlements. Allow up to 900 seconds for this example to cover creation and cleanup:

import browser from 'lexmount:browser';

const session = await browser.create({ browserMode: 'normal' });
try {
  console.log('Session:', session.sessionId);
  console.log(await session.openUrl('https://example.com'));
  const { targets } = await session.targets();
  const page = targets.find((target) => target.type === 'page');
  if (!page) throw new Error('Page target was not found');
  const options = { targetId: page.id, timeoutMs: 30000 };

  await session.waitSelector('h1', options);
  const result = await session.waitText('Example Domain', {
    ...options,
    selector: 'h1',
    exact: true,
  });
  if (result.timed_out) throw new Error('Expected heading was not found');
  console.log(await session.eval('document.title', options));
  console.log('PNG bytes:', (await session.screenshot(options)).length);
  console.log('Snapshot:', JSON.stringify(await session.snapshot(options)));
} finally {
  await session.destroy();
}

Screenshots return PNG bytes; this logs their length. To retain a file, call host.fs.writeFile(path, bytes) on a client with write permission. Form interaction uses session.fill(selector, value, options) and session.click(selector, options); PDF export uses session.pdf(options).

The example explicitly closes its created session in finally. Attach to an existing session with browser.get(sessionId) without taking automatic cleanup ownership. See browser capabilities for additional options.

Discover clients

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

for (const info of await getRemoteHosts()) {
  console.log(JSON.stringify(info));
  console.log('Available handle:', remoteHosts[info.id].id);
}

Host records include client ID, OS, CPU, and memory information. An empty list means no clients are currently available. Subsequent examples select a specific ID to target the intended computer.

Read files and directories

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

await getRemoteHosts();
const host = remoteHosts['<client-id>'];
if (!host) throw new Error('Client is offline or unavailable');

let count = 0;
for await (const entry of host.fs.readDir('.')) {
  console.log(entry.name, entry.isDirectory);
  if (++count >= 10) break;
}
const path = 'README.md'; // Replace with an existing file on the client.
console.log(await host.fs.stat(path));
console.log((await host.fs.readTextFile(path)).slice(0, 2000));

The output contains up to 10 directory entries, file metadata, and the first 2000 text characters. readTextFile still reads the whole file; truncating the displayed text does not limit read memory.

Write a file

Enable fs.allow_write first. This example creates a dedicated directory and overwrites its result.txt:

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

await getRemoteHosts();
const host = remoteHosts['<client-id>'];
if (!host) throw new Error('Client is offline or unavailable');

await host.fs.mkdir('runtime-docs-example', { recursive: true });
await host.fs.writeTextFile('runtime-docs-example/result.txt', 'Hello runtime\n');
await host.fs.writeTextFile('runtime-docs-example/result.txt', 'Second line\n', {
  create: false,
  append: true,
});
console.log(await host.fs.readTextFile('runtime-docs-example/result.txt'));

For bytes, use writeFile(path, new TextEncoder().encode(text)). To remove the example directory, call remove('runtime-docs-example', { recursive: true }).

Request a service on the client's local or private network

Replace the URL with an HTTP(S) service reachable by the client. This example expects an existing /health endpoint on the client's port 8080 and applies a five-second cancellation timer to both the request and body read:

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

await getRemoteHosts();
const host = remoteHosts['<client-id>'];
if (!host) throw new Error('Client is offline or unavailable');

const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5000);
try {
  const response = await host.fetch('http://127.0.0.1:8080/health', {
    signal: controller.signal,
  });
  const text = await response.text();
  if (!response.ok) throw new Error(`HTTP ${response.status}: ${text}`);
  console.log(response.status, text);
} finally {
  clearTimeout(timer);
  controller.abort();
}

Here, 127.0.0.1 refers to the client computer. Global fetch would originate in the cloud and would reject this local address.

Inspect and execute processes

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

await getRemoteHosts();
const host = remoteHosts['<client-id>'];
if (!host) throw new Error('Client is offline or unavailable');

let count = 0;
for await (const process of host.process.list()) {
  console.log(process.pid, process.name);
  if (++count >= 10) break;
}
const result = await host.process.exec('echo hello');
console.log(new TextDecoder().decode(result.stdout));
console.error(new TextDecoder().decode(result.stderr));
if (result.exitCode !== 0) throw new Error(`Exit code: ${result.exitCode}`);

Queries require process.enabled; execution also requires process.allow_exec. Decode stdout and stderr from bytes. This example buffers the complete output before displaying it.

Streaming processes and stdin

This example requires a Linux / macOS client with cat. It consumes both output streams concurrently, writes input, and closes stdin so cat receives EOF and exits:

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

await getRemoteHosts();
const host = remoteHosts['<client-id>'];
if (!host) throw new Error('Client is offline or unavailable');

const child = await host.process.spawn('cat');
try {
  const [, stdout, stderr, status] = await Promise.all([
    (async () => {
      const writer = child.stdin.getWriter();
      try {
        await writer.write(new TextEncoder().encode('Hello stdin\n'));
        await writer.close();
      } finally {
        writer.releaseLock();
      }
    })(),
    new Response(child.stdout).text(),
    new Response(child.stderr).text(),
    child.status,
  ]);
  console.log({ stdout, stderr, exitCode: status.exitCode });
  if (status.exitCode !== 0) throw new Error(`Exit code: ${status.exitCode}`);
} catch (error) {
  await child.kill().catch(() => {});
  throw error;
}

The output should include Hello stdin. Response.text() collects the small sample output. For large output, use two concurrent reader loops to process chunks without retaining the full contents.

Connect and listen over TCP

Allocate a temporary client-loopback port, connect to it, and echo some bytes. This requires tcp.enabled. Send write EOF, continue reading the echo, then close connections and the listener separately:

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

await getRemoteHosts();
const host = remoteHosts['<client-id>'];
if (!host) throw new Error('Client is offline or unavailable');

const listener = await host.tcp.listen({ hostname: '127.0.0.1', port: 0 });
const serving = (async () => {
  const incoming = await listener.accept();
  if (!incoming) return;
  try {
    await incoming.readable.pipeTo(incoming.writable);
  } finally {
    await incoming.close();
  }
})();

try {
  const connection = await host.tcp.connect(listener.addr);
  try {
    const writer = connection.writable.getWriter();
    try {
      await writer.write(new TextEncoder().encode('Hello TCP\n'));
      await writer.close();
    } finally {
      writer.releaseLock();
    }
    console.log(await new Response(connection.readable).text());
  } finally {
    await connection.close();
  }
} finally {
  await listener.close();
  await serving;
  await listener.finished;
}

The output should include Hello TCP. To reach another service, replace the connect argument with { hostname, port }. Listening addresses and reachability depend on the client's network.

Listen for HTTP on the client

Start a loopback HTTP service on a free port, then request it through the same client. This requires http_server.enabled and does not publish a public task URL.

import { getRemoteHosts, remoteHosts } from 'lexmount:remote';

await getRemoteHosts();
const host = remoteHosts['<client-id>'];
if (!host) throw new Error('Client is offline or unavailable');

const server = await host.http.serve({
  hostname: '127.0.0.1',
  port: 0,
  fetch(request) {
    return Response.json({ path: new URL(request.url).pathname });
  },
});
try {
  const url = `http://${server.addr.hostname}:${server.addr.port}/hello`;
  const response = await host.fetch(url);
  console.log(await response.json());
} finally {
  await server.shutdown();
  await server.finished;
}

The output is {"path":"/hello"}. To keep serving, wait for server.finished instead and access its actual address from another program. Task cleanup releases the listener when execution ends.

Capabilities

JavaScript APIs, remote files and processes, HTTP/TCP, cloud browser methods, and client permissions.

Capability FAQ

Understand persistent contexts, custom extensions, proxies, and stored downloads in Browser plans.

Table of Contents

Publish a public HTTP service
Cloud browser navigation, screenshots, and snapshots
Discover clients
Read files and directories
Write a file
Request a service on the client's local or private network
Inspect and execute processes
Streaming processes and stdin
Connect and listen over TCP
Listen for HTTP on the client

Still need help?Ask on Discord