Have your agent record video demos of its work with shot-scraper video

Simon Willison's Blog Tools

Summary

shot-scraper 1.10 introduces a new 'shot-scraper video' command that uses Playwright to record video demos of web application routines, enabling coding agents to produce visual proof of their work.

No content available
Original Article
View Cached Full Text

Cached at: 06/30/26, 07:36 PM

# Have your agent record video demos of its work with shot-scraper video Source: [https://simonwillison.net/2026/Jun/30/shot-scraper-video/](https://simonwillison.net/2026/Jun/30/shot-scraper-video/) 30th June 2026 [shot\-scraper video](https://shot-scraper.datasette.io/en/stable/video.html)is a new command introduced in today’s[shot\-scraper 1\.10](https://github.com/simonw/shot-scraper/releases/tag/1.10)release which accepts a`storyboard\.yml`file defining a routine to run against a web application and uses Playwright to record a video of that routine\. I’ve written before about the importance of[having coding agents produce demos](https://simonwillison.net/2026/Feb/10/showboat-and-rodney/#proving-code-actually-works)of their work; this is my latest attempt at enabling them to do that\. Here’s an example video created using`shot\-scraper video`, exercising a[still in development](https://github.com/simonw/datasette/pull/2813)feature adding the ability to create new tables in Datasette from pasted CSV, TSV or JSON data: That video was createdby running this command: ``` shot-scraper video datasette-bulk-insert-storyboard.yml \ --auth datasette-demo-auth.json --mp4 ``` \(That`\-\-auth`JSON file[contains a cookie](https://gist.github.com/simonw/287b26aff53fcb72942b19f5b69d7e5c), as[described here](https://shot-scraper.datasette.io/en/stable/authentication.html)in the documentation\.\) Here’s the`datasette\-bulk\-insert\-storyboard\.yml`file: ``` output: /tmp/datasette-bulk-insert-demo.webm server: - uv - --directory - /Users/simon/Dropbox/dev/datasette - run - datasette - -p - 6419 - --root - --secret - "1" - /tmp/demo.db url: http://127.0.0.1:6419/demo/tasks viewport: width: 1280 height: 720 cursor: true wait_for: 'button[data-table-action="insert-row"]' javascript: | (() => { let clipboardText = ""; Object.defineProperty(navigator, "clipboard", { configurable: true, get: () => ({ writeText: async (text) => { clipboardText = String(text); }, readText: async () => clipboardText, }), }); })(); scenes: - name: Bulk insert existing table rows do: - pause: 0.8 - click: 'button[data-table-action="insert-row"]' - wait_for: "#row-edit-dialog[open]" - pause: 0.5 - click: ".row-edit-bulk-insert" - wait_for: ".row-edit-bulk-textarea" - pause: 0.5 - click: ".row-edit-copy-template" - wait_for: "text=Copied" - pause: 0.8 - fill: into: ".row-edit-bulk-textarea" text: | title,owner,status,priority,notes Prepare release video,Ana,doing,1,Recorded with shot-scraper Check pasted CSV import,Ben,review,3,Previewed before inserting Share the branch demo,Chen,queued,2,Bulk insert creates three rows - pause: 0.8 - click: ".row-edit-save" - wait_for: "text=Previewing 3 rows." - pause: 1.2 - click: ".row-edit-save" - wait_for: "text=3 rows inserted." - pause: 1.0 - click: ".row-edit-cancel" - wait_for: "text=Prepare release video" - pause: 1.0 - name: Create a table from pasted CSV open: http://127.0.0.1:6419/demo wait_for: 'details.actions-menu-links summary' do: - pause: 0.8 - click: 'details.actions-menu-links summary' - click: 'button[data-database-action="create-table"]' - wait_for: "#table-create-dialog[open]" - pause: 0.5 - fill: into: ".table-create-table-name" text: "launch_metrics" - click: ".table-create-from-data" - wait_for: ".table-create-data-textarea" - pause: 0.5 - fill: into: ".table-create-data-textarea" text: | metric_id,name,score,recorded_on m001,Activation rate,87.5,2026-06-29 m002,Retention check,72.25,2026-06-30 m003,CSV import health,95,2026-07-01 - pause: 0.8 - click: ".table-create-save" - wait_for: "text=Previewing 3 rows." - pause: 1.2 - click: ".table-create-save" - wait_for_url: "**/demo/launch_metrics" - wait_for: "text=Activation rate" - pause: 1.2 ``` The[video command documentation](https://shot-scraper.datasette.io/en/stable/video.html)includes simpler examples, but for the purpose of this post I thought I’d go with something more comprehensive\. That demo YAML storyboard was constructed entirely by GPT\-5\.5 xhigh running in Codex Desktop, using the following prompt run inside my`~/dev/datasette`checkout of[this branch](https://github.com/simonw/datasette/commits/b759ea548606bc9bf9a4bf0e33e2d57ead7e0ab8/): > `Review the changes on this branch\.` `cd to ~/dev/shot\-scraper and run the command "uv run shot\-scraper video \-\-help"` `Now use that new video command to record a video demo of the new features from this branch, including running a "uv run datasette \-p 6419 \-\-root \-\-secret 1 /tmp/demo\.db" development server so you can record the video against a demo DB that you first create\.` Now that I’ve released the feature the prompt could say "`run uvx shot\-scraper video \-\-help`" instead and it should achieve the same result\. I really like this pattern where the`\-\-help`output for a command provides enough detail that a coding agent can use it—it works kind of like bundling a`SKILL\.md`file directly inside the tool\. I used the same pattern for[showboat and rodney](https://simonwillison.net/2026/Feb/10/showboat-and-rodney/)\. #### How I built this `shot\-scraper video`started as an experimental prototype\.`shot\-scraper`is built on top of[Playwright](https://playwright.dev/), and the key feature it needed was for Playwright to be able to record video of browser sessions with enough control to create the desired demo\. I first tried this a few years ago and found that the Playwright\-produced videos included additional chrome that was useful for debugging a test failure but unwanted for a product demo\. They fixed that a while ago, but there were still some minor blockers\. In particular I was getting[a few white frames at the start of the videos](https://github.com/simonw/shot-scraper/pull/194/changes/c2f3b3a52ba84f2adcf3ad6da4d39c2570328584#issuecomment-4724459369), since the recording mechanism kicked in before the first URL was loaded by the browser\. Playwright 1\.59 added a new[screencast mechanism](https://playwright.dev/python/docs/api/class-screencast)providing much more finely grained control over video recording\. This was very nearly what I needed, but the resulting videos were fixed at 800px wide\. I found a[landed PR fixing that](https://github.com/microsoft/playwright/pull/41183)but it wasn’t yet in a release\. Then yesterday they shipped it in[playwright\-python 1\.61\.0](https://github.com/microsoft/playwright-python/releases/tag/v1.61.0)and I was finally unblocked to finish implementing the feature\! The code itself was all written by GPT\-5\.5 xhigh in Codex Desktop\. I had it write the documentation as well which gave me a very useful frame for reviewing the design—much of the iteration on the feature came from reviewing that documentation, spotting things that were redundant, inconsistent or confusing, and requesting \(or dictating\) a better design\. The YAML format itself was mostly defined by the coding agent\. I had it[use Pydantic](https://github.com/simonw/shot-scraper/blob/1.10/shot_scraper/video.py#L24)to both define and validate the format, partly to make the design easier to review\. This is a great example of the kind of feature that I almost certainly wouldn’t have taken on without coding agent support\. I filed the[original issue](https://github.com/simonw/shot-scraper/issues/142)in February 2024, and had difficulty finding the necessary time to solve this in amongst all of my other projects\.

Similar Articles

Slideshot

Product Hunt

Slideshot is an AI agent that records product demo videos.

A new agentic way to build automations

Reddit r/AI_Agents

A new tool lets users screen record themselves performing a task; an agent learns the task and builds a deterministic script to automate it, with fallback handling when scripts break.