https://github.com/browserbox/hyper-frame
Hyper-Frame — an iframe that can frame any website. The <hyper-frame> custom element (@browserbox/hyper-frame).
https://github.com/browserbox/hyper-frame
Last synced: about 1 month ago
JSON representation
Hyper-Frame — an iframe that can frame any website. The <hyper-frame> custom element (@browserbox/hyper-frame).
- Host: GitHub
- URL: https://github.com/browserbox/hyper-frame
- Owner: BrowserBox
- License: agpl-3.0
- Created: 2026-02-11T03:35:30.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-04-26T08:59:01.000Z (2 months ago)
- Last Synced: 2026-04-26T09:32:07.856Z (2 months ago)
- Language: JavaScript
- Homepage: https://browserbox.github.io/hyper-frame/
- Size: 121 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Hyper-Frame
**`` — an iframe that can frame any website.**
Install via npm:
```bash
npm i --save @browserbox/hyper-frame
```
```html
```
Before starting a self-hosted BrowserBox instance set the allowed embedder origins:
```bash
export ALLOWED_EMBEDDING_ORIGINS="https://your-site.example.com https://other-embedder.example.com"
bbx stop
bbx setup -p 8888
bbx start
cat ~/.config/dosaygo/bbpro/login.link
```
## Quick Start
```js
const bbx = document.querySelector('hyper-frame');
await bbx.whenReady();
await bbx.page.navigate('https://example.com');
const tabs = await bbx.tabs.list();
const firstTab = tabs[0];
if (firstTab?.id) {
await bbx.tabs.activate(firstTab.id);
}
await bbx.click('a.my-link');
await bbx.waitForSelector('.result');
const title = await bbx.evaluate('document.title');
const screenshot = await bbx.capture.frame({ format: 'jpeg', quality: 80 });
await bbx.frameCapture(true);
const frame = await bbx.getFrame();
await bbx.cleanSlate('https://example.com');
```
## Element Attributes
| Attribute | Required | Default | Description |
|-----------|----------|---------|-------------|
| `login-link` | yes | — | Full BrowserBox login URL with auth token |
| `width` | no | `"100%"` | CSS width (px if bare number) |
| `height` | no | `"100%"` | CSS height (px if bare number) |
| `embedder-origin` | no | `"*"` | Restrict postMessage origin |
| `request-timeout-ms` | no | `30000` | API call timeout (ms) |
| `ui-visible` | no | `true` | Show/hide BrowserBox chrome UI |
| `allow-user-toggle-ui` | no | `true` | Allow user to toggle UI visibility |
| `interaction-mode` | no | `"full"` | Policy preset: `full`, `limited`, `view-only` |
| `policy` | no | — | Additional local policy restrictions |
| `chrome` | no | `"default"` | Chrome presentation hint: `none`, `minimal`, `default`, `custom` |
| `augment-root` | no | `"open"` | Augment inspectability hint: `open` or `closed` |
| `capture` | no | `"snapshot"` | Capture policy hint: `off`, `snapshot`, `sampled` |
| `media-permissions` | no | `"default"` | Set to `"none"` to deny mic/camera/display-capture |
| `session-unload-warning` | no | `"default"` | Set to `"none"` to suppress beforeunload warning |
| `beforeunload-behavior` | no | `"default"` | `"leave"` to auto-depart, `"remain"` to auto-stay |
| `first-load-cleanse` | no | — | Close all tabs on first session load; if the value is a URL, open that URL after cleansing |
`first-load-cleanse` runs once for each `login-link`. Use a non-empty URL to close existing tabs and open that replacement tab. Use an empty value, such as `first-load-cleanse=""`, to close existing tabs without opening a replacement. The `firstLoadCleanse(url?)` method follows the same rule: a non-empty string opens that URL, and an empty string performs the delete-only cleanse.
## Namespaced API
Access via the element (`bbx.tabs.list()`) or via `bbx.session` facade.
### `session`
| Property / Method | Returns | Description |
|-------------------|---------|-------------|
| `session.id` | `string \| null` | Routing machine ID |
| `session.usable` | `boolean` | Whether session is usable |
| `session.ready` | `boolean` | Whether API handshake completed |
| `session.transport` | `string` | Transport mode |
| `session.health()` | `Promise` | Probe browser and transport |
| `session.capabilities()` | `Promise` | Query supported capabilities |
| `session.disconnect()` | `void` | Tear down the session |
| `session.refresh()` | `void` | Reload the embedded iframe |
### `tabs`
| Method | Returns | Description |
|--------|---------|-------------|
| `tabs.list()` | `Promise` | List all open tabs |
| `tabs.getActive()` | `Promise` | Get the active tab |
| `tabs.create({ url, active? })` | `Promise` | Open a new tab |
| `tabs.activate(tabId)` | `Promise` | Switch to a tab by ID |
| `tabs.close(tabId)` | `Promise` | Close a tab by ID |
| `tabs.closeAll()` | `Promise` | Close all tabs |
### `page`
| Method | Returns | Description |
|--------|---------|-------------|
| `page.navigate(url, opts?)` | `Promise` | Navigate the active tab |
| `page.url()` | `Promise` | Active tab URL |
| `page.title()` | `Promise` | Active tab title |
| `page.reload()` | `Promise` | Reload the active tab |
| `page.back()` | `Promise` | Navigate back |
| `page.forward()` | `Promise` | Navigate forward |
| `page.stop()` | `Promise` | Stop loading |
| `page.text(opts?)` | `Promise` | Extract page text |
| `page.metrics()` | `Promise` | Viewport/document dimensions |
### `capture`
| Method | Returns | Description |
|--------|---------|-------------|
| `capture.frame(opts?)` | `Promise` | Full-page screenshot |
| `capture.viewport(opts?)` | `Promise` | Viewport screenshot |
| `capture.enable(enabled?)` | `Promise` | Enable/disable frame capture |
| `capture.next()` | `Promise` | Consume latest frame |
## Events
| Event | Detail | Description |
|-------|--------|-------------|
| `ready` | `{ type }` | Legacy handshake completed |
| `api-ready` | `{ methods, policy? }` | Modern API available |
| `ready-timeout` | `{ timeoutMs, error }` | Handshake timed out |
| `tab-created` | `{ index, id, url }` | New tab opened |
| `tab-closed` | `{ index, id }` | Tab closed |
| `tab-updated` | `{ id, url, title, faviconDataURI }` | Tab metadata updated |
| `active-tab-changed` | `{ index, id }` | Active tab switched |
| `did-navigate` | `{ tabId, url }` | Navigation committed |
| `policy-denied` | `{ url, reason }` | Navigation blocked |
| `usability-changed` | `{ usable: boolean }` | Usability state changed |
| `sos` | `{ reasonCode, message, retryUrl }` | Fatal unusable signal |
| `disconnected` | — | Session ended |
## Errors
API failures use stable `BrowserBoxError` codes: `ERR_NOT_READY`, `ERR_POLICY_DENIED`, `ERR_TIMEOUT`, `ERR_TRANSPORT`, `ERR_UNSUPPORTED`, `ERR_INVALID_ARGUMENT`, `ERR_NOT_FOUND`, `ERR_CONFLICT`, `ERR_INTERNAL`.
## License
AGPL-3.0-or-later