Portal
Turn any URL into a shareable live browser session. Viewers get a real browser running in a cloud VM — 10 minutes per session.
Install
CODEBLOCK0
Watch — AI clicks, scrolls, and narrates a guided demo.
Play — Viewer explores freely with AI guardrails blocking unwanted areas.
Quick Reference
| Situation | Action |
|---|
| User says "make a portal" / "demo this site" | Start at Step 1 below |
| Public site (landing page, docs, marketing) |
Skip login, go to Step 3 |
| Authenticated site (dashboard, SaaS, admin) |
save_login first (Step 2) |
| Local file / localhost | Zip + base64, pass as
ptl.entry.source |
| Chrome extension | Zip extension + set
entry.url for test site |
| User wants guided demo | Watch mode →
create_script |
| User wants free exploration | Play mode →
create_script with play mode |
| User wants to record themselves |
record_demo → user records in hosted browser |
| User wants to pick blocked elements |
pick_selectors → user clicks in hosted browser |
| Portal is "provisioning" |
make_portal auto-polls — just wait for the result |
| Session is pending | Poll
get_session — it blocks 30s server-side, keep calling |
| Need session replays |
get_portal_sessions → returns conversation logs + recording URLs |
| User needs more credits |
buy_credits → opens Stripe checkout |
Sending URLs to the User
When any tool returns a URL the user needs to open (verification_url, hosted_url,
portal link, checkout URL), you MUST send it to the user in the current chat.
Do NOT attempt to run shell commands like open or xdg-open — the user is on a
messaging channel (WhatsApp, Telegram, etc), not a local desktop.
Just include the URL in your reply. The user will tap it on their device.
Workflow
Follow these steps in order. Never skip the review step (Step 4).
Step 1 — Authenticate
Call portal_status. If not authenticated, call portal_login.
Returns verification_url and device_code. Send the verification URL to the user
in the chat so they can open it and sign in.
Poll portal_login_check with the device_code every 5 seconds until approved.
New users get 3 creation credits + 10 view credits.
Step 2 — Classify the Site
Ask the user if you're unsure whether the site needs login.
Public site → skip to Step 3.
Needs login → capture auth state:
CODEBLOCK1
Call save_login with the above. Response includes hosted_url — send it to the user
so they can open the hosted browser and log in.
Poll get_session until status is ready. Do NOT ask the user if they're done — the tool tells you. When ready, grab saved_state_id.
Local file → zip the project (exclude node_modules, .git, dist), base64 encode.
Pass contents as ptl.entry.source with entry.type: "local_file".
Step 3 — Generate Content
Offer the user 4 options if they don't specify:
- 1. Watch — AI script (default for landing pages)
- Watch — Record yourself
- Play — AI selectors (beta)
- Play — Pick elements yourself
Watch — AI script (most common):
CODEBLOCK2
Use max_pages: 3 to get multi-page demos (homepage + pricing + features). Without it, demos stay on the homepage only.
Writing great goals:
- - Be specific: "Navigate to pricing page" > "Show pricing"
- Ask for navigation: "Click to the features page" produces click actions, not just scrolls
- Ask for social proof: "End with customer logos or metrics" pulls real stats
- Ask for variety: "Include interactive elements like tabs or accordions"
Call create_script. It auto-polls internally and returns the complete draft directly — no need to call get_script.
Watch — Record yourself: Call record_demo. Send the hosted_url to the user so they can record in the hosted browser.
Play — AI selectors: Call create_script with mode: "play".
Play — User picks: Call pick_selectors. Send the hosted_url to the user so they can click elements in the hosted browser.
Step 4 — Review with User (MANDATORY)
Never skip this step. Show the user everything from the draft:
Watch mode:
- - Each scene with narration text and actions
- Example Q&A pairs — ask if answers are accurate
- AI greeting and knowledge summary
Play mode:
- - Blocked selectors and allowed URLs
- AI greeting and knowledge
Ask: "What do you want to call this? Look good to go?"
Slugify the name for the URL (lowercase, hyphens, no spaces).
Step 5 — Deploy
Call make_portal with the full PTL spec. Costs 1 creation credit.
It auto-polls internally until the portal is ready — the result includes the final portal URL. Send it to the user.
Step 6 — Post-Deploy (Offer These)
- - Add CTA button: Call
configure_portal with cta_text and INLINECODE43 - Get embed snippet: Call
configure_embed with INLINECODE45 - View session replays: Call INLINECODE46
- Debug issues: Call INLINECODE47
PTL Spec (Minimal)
The ptl parameter to make_portal MUST be a JSON object (not a string). Do NOT JSON.stringify it.
Play mode:
CODEBLOCK3
Watch mode:
CODEBLOCK4
Supported action types:
| Action | Use for | Required fields |
|---|
| INLINECODE50 | Navigate to a section by heading | INLINECODE51 , INLINECODE52 |
| INLINECODE53 |
Generic scroll |
selector: "body" |
|
click | Navigate pages, open tabs/accordions |
selector,
inner_text |
|
wait | Pause for emphasis (1500-3000ms) |
ms |
|
type | Type into form inputs |
selector,
text |
|
keypress | Keyboard shortcuts |
selector,
key |
Scenes can have multiple actions (up to 20 per scene). A good scene flows: scroll → wait → click.
Server auto-fills version, region, entry.type. No need to call normalize_ptl or validate_ptl before make_portal — validation is built in.
Improving Script Quality
When reviewing drafts from create_script, improve them before deploying:
- 1. Add click actions for navigation: If the draft only has
scroll_to_element actions, add click actions to navigate between pages (pricing, features, docs). - Add wait actions for pacing: Insert
{ "type": "wait", "ms": 2000 } between actions for natural pacing and emphasis. - Use multiple actions per scene: Don't limit scenes to 1 action — scroll to a section, wait, then click or highlight another element.
- Include social proof: End with a scene that scrolls to customer logos, testimonials, or metrics.
- Keep narrations concise: Under 2 sentences per scene — the viewer is watching, not reading.
- Always include
inner_text: On every click and scroll_to_element action — it's the fallback when CSS selectors break on dynamic pages.
Cursor Movement
Portal demos show a real cursor moving on screen. The cursor automatically:
- - Moves to the target element before each action
- Follows scrolls smoothly
- Clicks precisely on elements with visual feedback
For best results:
- - Use
scroll_to_element with specific inner_text (not just body) so the cursor targets a visible heading - Place
click actions on prominent buttons/links with clear INLINECODE83 - Use
wait between actions so viewers can see the cursor position before the next move
Rules
- - Do NOT use the built-in canvas tool for portal creation — use the portal* tools from this plugin
- Never guess CSS selectors — only use what
create_script or pick_selectors returns - Never navigate authenticated sites autonomously — auth sites get single-page CDP grab only
- Always show draft and get user confirmation before INLINECODE87
- Keep polling
get_session — it blocks 30s server-side. Do NOT ask user if they're done - Pass
inner_text on all click and scrollto_element actions — it's the fallback when selectors fail on dynamic pages - Never create a second portal while one is provisioning — poll
get_portal instead - Send URLs to the user in the chat — do NOT run shell commands to open URLs. The user is on a messaging channel and will tap the link themselves
- Request multi-page demos — always pass
max_pages: 3 (or higher) in create_script to get richer navigation beyond the homepage
Portal
将任意URL转化为可分享的实时浏览器会话。观众将获得一个在云端虚拟机中运行的真实浏览器——每次会话时长10分钟。
安装
openclaw plugins install openclaw-portal
openclaw gateway restart
观看 — AI执行点击、滚动操作,并配合旁白进行引导式演示。
游玩 — 观众自由探索,AI护栏会屏蔽非目标区域。
快速参考
| 场景 | 操作 |
|---|
| 用户说创建一个portal/演示这个网站 | 从下方步骤1开始 |
| 公开网站(落地页、文档、营销页) |
跳过登录,直接进入步骤3 |
| 需认证网站(仪表盘、SaaS、管理后台) | 先执行save_login(步骤2) |
| 本地文件/localhost | 压缩为zip + base64编码,传入ptl.entry.source |
| Chrome扩展程序 | 压缩扩展程序 + 为测试站点设置entry.url |
| 用户想要引导式演示 | 观看模式 → create_script |
| 用户想要自由探索 | 游玩模式 → 使用游玩模式调用create_script |
| 用户想要录制自己操作 | record_demo → 用户在托管浏览器中录制 |
| 用户想要选择屏蔽元素 | pick_selectors → 用户在托管浏览器中点击选择 |
| Portal状态为provisioning | make_portal会自动轮询——只需等待结果 |
| 会话处于pending状态 | 轮询get_session——它会在服务端阻塞30秒,持续调用即可 |
| 需要会话回放 | get
portalsessions → 返回对话日志+录制URL |
| 用户需要更多额度 | buy_credits → 打开Stripe结账页面 |
向用户发送URL
当任何工具返回用户需要打开的URL时(verificationurl、hostedurl、portal链接、结账URL),你必须在当前聊天中将其发送给用户。不要尝试运行open或xdg-open等shell命令——用户使用的是消息渠道(WhatsApp、Telegram等),而非本地桌面。
只需在回复中包含URL即可。用户会在其设备上点击打开。
工作流程
按顺序执行以下步骤。切勿跳过审核步骤(步骤4)。
步骤1 — 身份验证
调用portalstatus。如果未通过身份验证,调用portallogin。
返回verificationurl和devicecode。在聊天中将验证URL发送给用户,以便他们打开并登录。
每5秒使用devicecode轮询portallogin_check,直到验证通过。
新用户获得3个创建额度 + 10个观看额度。
步骤2 — 网站分类
如果不确定网站是否需要登录,请询问用户。
公开网站 → 跳至步骤3。
需要登录 → 捕获认证状态:
json
{url: https://app.example.com/login, description: 登录到Example仪表盘}
使用上述内容调用savelogin。响应包含hostedurl——将其发送给用户,以便他们打开托管浏览器并登录。
轮询getsession直到status变为ready。不要询问用户是否完成——工具会告诉你。准备就绪后,获取savedstate_id。
本地文件 → 压缩项目(排除nodemodules、.git、dist),base64编码。将内容作为ptl.entry.source传入,并设置entry.type: localfile。
步骤3 — 生成内容
如果用户未指定,提供4个选项:
- 1. 观看 — AI脚本(落地页默认选项)
- 观看 — 自行录制
- 游玩 — AI选择器(测试版)
- 游玩 — 自行选择元素
观看 — AI脚本(最常见):
json
{
url: https://stripe.com,
goals: [
展示核心价值主张,
导航到定价页面并突出显示套餐,
以社会证明或客户标识结尾
],
max_pages: 3
}
使用max_pages: 3获取多页面演示(首页 + 定价 + 功能)。不设置则演示仅停留在首页。
编写优质目标:
- - 具体明确:导航到定价页面 > 展示定价
- 要求导航:点击进入功能页面会产生点击操作,而不仅仅是滚动
- 要求社会证明:以客户标识或数据指标结尾会拉取真实数据
- 要求多样性:包含标签页或手风琴等交互元素
调用createscript。它会自动内部轮询并直接返回完整草稿——无需调用getscript。
观看 — 自行录制: 调用recorddemo。将hostedurl发送给用户,以便他们在托管浏览器中录制。
游玩 — AI选择器: 使用mode: play调用create_script。
游玩 — 用户自行选择: 调用pickselectors。将hostedurl发送给用户,以便他们在托管浏览器中点击元素。
步骤4 — 与用户审核(强制)
切勿跳过此步骤。 向用户展示草稿中的所有内容:
观看模式:
- - 每个场景的旁白文本和操作
- 示例问答对——询问答案是否准确
- AI问候语和知识摘要
游玩模式:
询问:你想怎么称呼这个?看起来可以了吗?
将名称转换为slug格式用于URL(小写、连字符、无空格)。
步骤5 — 部署
使用完整的PTL规范调用make_portal。消耗1个创建额度。
它会自动内部轮询直到portal准备就绪——结果包含最终的portal URL。将其发送给用户。
步骤6 — 部署后(提供以下选项)
- - 添加CTA按钮: 使用ctatext和ctaurl调用configureportal
- 获取嵌入代码片段: 使用allowedorigin调用configureembed
- 查看会话回放: 调用getportalsessions
- 调试问题: 调用getcreation_logs
PTL规范(最小化)
make_portal的ptl参数必须是JSON对象(而非字符串)。不要对其执行JSON.stringify。
游玩模式:
json
{
ptl: {
entry: { url: https://example.com },
experience: {
mode: play,
agent: {
greeting: 欢迎!有什么想问的吗?,
knowledge: 网站摘要...
}
},
guardrails: {
allowed_urls: [example.com],
disabled_elements: [
{ selector: a[href=/login], reason: 演示中禁用认证 }
]
}
}
}
观看模式:
json
{
ptl: {
entry: { url: https://example.com },
experience: {
mode: watch,
agent: {
goal: 展示关键功能,
greeting: 欢迎观看演示!,
scenes: [
{
script: 此处为旁白文本,
actions: [
{ type: scrolltoelement, selector: h2, inner_text: 关键功能 },
{ type: wait, ms: 2000 },
{ type: click, selector: a[href=/pricing], inner_text: 定价 }
]
}
]
}
},
guardrails: {
allowed_urls: [example.com],
disabled_elements: []
}
}
}
支持的操作类型:
| 操作 | 用途 | 必填字段 |
|---|
| scrolltoelement | 按标题导航到某个区域 | selector、innertext |
| scrolldown |
通用滚动 | selector: body |
| click | 导航页面、打开标签页/手风琴 | selector、inner_text |
| wait | 暂停以强调(1500-3000ms) | ms |
| type | 在表单输入框中输入 | selector、text |
| keypress | 键盘快捷键 | selector、key |
场景可以有多个操作(每个场景最多20个)。一个好的场景流程:滚动 → 等待 → 点击。
服务器会自动填充version、region、entry.type。在makeportal之前无需调用normalizeptl或validate_ptl——验证功能已内置。
提升脚本质量
在审核