diff --git a/src/content/run-on-lightpanda-cloud/_meta.ts b/src/content/run-on-lightpanda-cloud/_meta.ts
index a500e94..62ba41c 100644
--- a/src/content/run-on-lightpanda-cloud/_meta.ts
+++ b/src/content/run-on-lightpanda-cloud/_meta.ts
@@ -2,6 +2,7 @@ import type { MetaRecord } from 'nextra'
const meta: MetaRecord = {
'getting-started': 'Getting started',
+ playground: 'Playground',
'limits-and-billing': 'Limits and billing',
}
diff --git a/src/content/run-on-lightpanda-cloud/getting-started.mdx b/src/content/run-on-lightpanda-cloud/getting-started.mdx
index 40d66b0..05c0035 100644
--- a/src/content/run-on-lightpanda-cloud/getting-started.mdx
+++ b/src/content/run-on-lightpanda-cloud/getting-started.mdx
@@ -101,9 +101,10 @@ The cloud serves Lightpanda by default. For debugging, append `browser=chrome` t
The same URL takes a `proxy` parameter to route the session through a shared proxy, or through one you added on the [proxies page](https://console.lightpanda.io/proxies) in the console.
-## Other features: HTTP API and MCP
+## Other features: playground, HTTP API and MCP
The cloud also exposes:
+- a **[playground](/run-on-lightpanda-cloud/playground)** to write and run a script from the console, with no local setup at all.
- an **[HTTP API](/usage/api)** to fetch a page's HTML or Markdown in a single request, with no CDP script.
- an **[MCP](/usage/mcp)** server to drive the browser from AI applications over the Model Context Protocol.
diff --git a/src/content/run-on-lightpanda-cloud/limits-and-billing.mdx b/src/content/run-on-lightpanda-cloud/limits-and-billing.mdx
index b3e4324..bd768d8 100644
--- a/src/content/run-on-lightpanda-cloud/limits-and-billing.mdx
+++ b/src/content/run-on-lightpanda-cloud/limits-and-billing.mdx
@@ -27,6 +27,8 @@ Upgrade, download invoices, or cancel from the [billing page](https://console.li
**Concurrent sessions** are the sessions open at one instant. This limit is about parallelism, not total volume: a plan's concurrency cap still lets you run many sessions a day, as long as no more than that cap overlap at once.
+Both limits apply regardless of how you open a session: over CDP, MCP, the HTTP API, or from the playground.
+
## When you reach a limit
If you open more sessions than your concurrency limit allows, the extra sessions are rejected with HTTP `429 Too Many Requests`. Retry once a running session ends, or upgrade for more concurrency.
diff --git a/src/content/run-on-lightpanda-cloud/playground.mdx b/src/content/run-on-lightpanda-cloud/playground.mdx
new file mode 100644
index 0000000..626f54f
--- /dev/null
+++ b/src/content/run-on-lightpanda-cloud/playground.mdx
@@ -0,0 +1,107 @@
+---
+title: Playground
+description: Write and run browser automation scripts from the Lightpanda Cloud console, with Puppeteer and Playwright preinstalled and no local setup.
+---
+
+import { Tabs, Callout } from 'nextra/components'
+
+# Playground
+
+The playground is a [code editor](https://console.lightpanda.io/playground/scripts) in the console that runs your automation scripts on Lightpanda Cloud.
+
+## Write and run a script
+
+Your script reaches the browser through `CDP_WS_URL`, an environment variable the playground sets for you:
+
+
+
+```js copy
+import { chromium } from 'playwright-core';
+
+// Connect Playwright's chromium driver to the browser.
+const browser = await chromium.connectOverCDP(process.env.CDP_WS_URL);
+
+const context = await browser.newContext({});
+const page = await context.newPage();
+
+await page.goto('https://wikipedia.com/');
+
+const title = await page.locator('h1').textContent();
+console.log(title);
+
+await page.close();
+await context.close();
+await browser.close();
+```
+
+
+```js copy
+import puppeteer from 'puppeteer-core';
+
+// Connect Puppeteer to the browser.
+const browser = await puppeteer.connect({
+ browserWSEndpoint: process.env.CDP_WS_URL,
+});
+
+const context = await browser.createBrowserContext();
+const page = await context.newPage();
+
+await page.goto('https://wikipedia.com/');
+
+const title = await page.$eval('h1', el => el.textContent);
+console.log(title);
+
+await page.close();
+await context.close();
+await browser.disconnect();
+```
+
+
+
+## What CDP_WS_URL contains
+
+You do not need to hard-code a token in your script. `CDP_WS_URL` holds the WebSocket address your client uses to reach the browser over the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) (CDP), assembled from the choices in the Default variables panel:
+
+| Default variable | Values | What it controls |
+| --- | --- | --- |
+| Region | `euwest`, `uswest` | Which region serves the browser |
+| Token | one of your active tokens | Which token the run authenticates with |
+| Browser | `lightpanda`, `chrome` | Which browser runs. Chrome is for debugging, not production traffic |
+| Proxy | one of your proxies, or none | The outbound IP the browser uses |
+
+Pass `process.env.CDP_WS_URL` to whichever client you use.
+
+
+`console.log(process.env.CDP_WS_URL)` prints `***`, not the URL. The URL carries an access token created for the run, and run output is stored in the console, so the playground masks the URL wherever it appears in output.
+
+
+## What the runtime provides
+
+Scripts run in an isolated container. Both CDP clients are preinstalled at fixed versions, so there is no install step:
+
+| Package | Version |
+| --- | --- |
+| `playwright-core` | 1.50.0 |
+| `puppeteer-core` | 24.0.0 |
+
+The rest of the environment is fixed too:
+
+- **Language.** JavaScript and TypeScript both run through [tsx](https://tsx.is/), so `import` syntax and top-level `await` work in either without configuration.
+- **Packages.** You cannot install anything beyond the two clients above.
+- **Filesystem.** Read-only, apart from a writable `/tmp`.
+
+Every run is capped:
+
+| Limit | Value |
+| --- | --- |
+| Run time | 5 minutes |
+| Memory | 256 MB |
+| CPU | 1 core |
+| Output captured | 256 KB |
+| Processes | 64 |
+
+A run that reaches 5 minutes stops and reports `timeout running program`. Output beyond 256 KB is dropped, and the run is flagged as truncated.
+
+These caps apply to the script process. The browser session driven by the script also counts toward your [plan limits](/run-on-lightpanda-cloud/limits-and-billing).
+
+The [Runs page](https://console.lightpanda.io/playground/script-runs) shows your run history and output for the past 30 days.
\ No newline at end of file
diff --git a/src/content/usage/cdp/playwright.mdx b/src/content/usage/cdp/playwright.mdx
index a214173..b7a80b3 100644
--- a/src/content/usage/cdp/playwright.mdx
+++ b/src/content/usage/cdp/playwright.mdx
@@ -61,6 +61,8 @@ await context.close();
await browser.close();
```
+In the [playground](/run-on-lightpanda-cloud/playground), the console builds this URL for you and exposes it as `CDP_WS_URL`. Pass `process.env.CDP_WS_URL` to `connectOverCDP` there, since `LPD_TOKEN` does not exist in that runtime.
+
## Cloud options
### Endpoints
diff --git a/src/content/usage/cdp/puppeteer.mdx b/src/content/usage/cdp/puppeteer.mdx
index c0725db..380b4ab 100644
--- a/src/content/usage/cdp/puppeteer.mdx
+++ b/src/content/usage/cdp/puppeteer.mdx
@@ -67,6 +67,7 @@ await context.close()
await browser.disconnect()
```
+In the [playground](/run-on-lightpanda-cloud/playground), the console builds this URL for you and exposes it as `CDP_WS_URL`. Pass `process.env.CDP_WS_URL` to `browserWSEndpoint` there, since `LPD_TOKEN` does not exist in that runtime.
## Cloud options