A free, open-source Chrome extension for previewing websites at phone sizes inside a device frame. It works right in your browser tab, without a separate app, account, server or paid plan.
- No debugger banner. The site loads in a real iframe, so Chrome does not show "started debugging this browser".
- One tab. The toolbar icon turns the current tab into the studio and back again. It does not open extra tabs or popup windows.
- Real interaction. Click, scroll, type, paste, use IME, file pickers and the Back button directly on the phone screen.
- Instant resize. Switch presets, set custom sizes and rotate without reloading the page.
- Side-by-side comparison. Show up to 4 devices at once. Navigation and scrolling stay in sync, including carousels and other inner scroll areas. Unlink a device to keep it on its own page.
- Screenshots. Save a PNG or copy it to the clipboard, with or without the device frame. Full page captures the whole page from top to bottom and shows sticky headers and fixed bars only once.
- Video recording. Record the devices to MP4 (WebM where MP4 is unavailable) for bug reports. Chrome asks to share the tab each time, and the video is cropped to the devices.
- Device library. Ten phone, tablet and desktop presets, plus custom sizes you name and keep.
- Zoom. Fit everything on screen, or view devices at true size (100%).
- Drag to scroll. A mouse drag scrolls the page or a carousel like a finger, glides on release, and never clicks what it started on. Form fields keep normal mouse behaviour.
- Mobile user agent. Switch the Studio between Desktop, iPhone and Android. Servers and page scripts both see the phone browser.
- Keyboard shortcuts. Press
?in the studio for the list.Alt+Shift+Vopens or closes Viewport from any tab. - Dark theme. Follows your system, or pick light or dark with the button in the header.
- Click and typing sync (experimental). Fill a form or open a menu once and the other devices follow.
- Private by design. No network calls, analytics, remote code or build step.
| Studio with three devices | Full-page capture (phone) |
|---|---|
![]() |
![]() |
- Download
viewport-studio-<version>.zipfrom the latest release and unzip it somewhere it can stay; Chrome loads it from there every time. (Or clone this repository and use itsextensionfolder.) - Open
chrome://extensionsand turn on Developer mode. - Click Load unpacked and select the unzipped folder.
Requires Chrome 128 or newer. Chromium-based browsers such as Edge should also work.
- Open the website or
localhostpage you want to test, then click the Viewport icon. - The first time, click Allow website access and approve Chrome's dialog. You only need to do this once.
- Type other addresses in the studio's address bar, or navigate inside the phone.
- Click a device in the list to switch the selected device, or click + next to it to add it alongside. Click a device's name above it to select it, × to remove it, or the link icon to take it out of sync.
- Type a width and height to make a custom size, then name it to save it under Saved.
- Click the icon again, press
Alt+Shift+V, or use Exit Viewport to return the tab to the last page you visited.
Most websites refuse to be shown inside an iframe (X-Frame-Options, CSP frame-ancestors). Viewport uses declarativeNetRequest session rules to remove those headers only for sub-frames inside the studio tab. Other tabs keep every site's framing protection. Viewport removes the rules when you leave the studio, navigate the tab elsewhere or close it. It removes CSP only when the policy contains frame-ancestors.
A small content script (frame.js) runs only when its direct parent is the studio (checked through location.ancestorOrigins). It hides desktop scrollbars, which would otherwise take about 15px of layout width. It also reports the page URL, and the scroll position while sync is on, to the studio over an extension port that the web page cannot forge. It exits immediately on every other page.
When you pick an iPhone or Android user agent, a session rule sets the User-Agent header (and the matching client hints) on requests from the Studio tab's devices, and agent.js changes navigator.userAgent, platform, vendor and userAgentData in the page's own world. agent.js only acts when its frame sits directly inside an extension page and carries a Studio device name.
| Permission | Why |
|---|---|
activeTab |
Read the URL of the tab where you clicked the icon. |
storage |
Keep the current page for the browser session, and your devices, layout and saved sizes across restarts. |
scripting |
Register frame.js and agent.js (http and https pages only). |
declarativeNetRequestWithHostAccess |
Apply the studio-only framing and user-agent rules. |
<all_urls> (optional) |
Requested once from the studio. It covers framing, login cookies inside the frame, frame.js and screenshots (captureVisibleTab requires <all_urls>). |
- Only the CSS viewport size and, if you pick one, the user agent match the device. Device pixel ratio, touch events and the
hover/pointermedia features stay desktop values, and iPhone presets still render with Chrome's engine, not Safari. - The user agent applies to every device in the Studio tab, because Chrome's request rules cannot target a single frame. iPad presets use the desktop agent, as iPadOS Safari does. Web workers keep the desktop agent.
- Pages without a viewport meta tag render at device width instead of the zoomed-out 980px layout that mobile browsers use.
- Inside the preview, Viewport ignores a site's CSP when that CSP contains
frame-ancestors. Test CSP-related issues in a normal tab. - Chrome blocks plain
http://addresses other than localhost (such ashttp://192.168.x.x) as mixed content. Uselocalhost,127.0.0.1or https. - A framebusting script that runs after a user click can take over the tab.
- While recording, the devices fill the window for a sharper video and a floating bar shows the clock and Stop. Recordings do not include the mouse pointer and stop by themselves after five minutes.
- Screenshot resolution depends on your screen. Devices are briefly shown alone at the largest size that fits the window, and the Viewport tab must stay in front until the screenshot is done.
- Full-page screenshots scroll the page one screen at a time (about 0.6 seconds per screen). Animations that play on scroll can look different from a normal visit, and extremely long pages are cut at 32,000 image pixels.
- Click and typing sync replays actions by element position in the page, like inner scroll sync. Links are left to navigation sync, and password and file fields are never copied. A replayed click includes the full press (pointer and mouse down/up), but drags, hovers and long presses are not replayed.
- Inner scroll areas are matched between devices by their position in the page. If a layout builds different markup per screen size, that area is not synced. A synced navigation fully loads the page in the other devices, including single-page-app route changes.
See ROADMAP.md for planned features.
There is no build step and the extension has no dependencies. You need Node.js 22 or newer to run the checks; only the browser tests install Playwright.
npm testnpm run checknpm test covers URL and size validation, session ownership, rule scoping and cleanup, the frame.js and agent.js gates, scroll, click and drag handling, layout math, stored-preference cleanup and translation coverage, all against mocked Chrome APIs.
The browser tests load the real extension in Chromium and drive it with real mouse and keyboard input: framing, devices side by side, screenshots, video recording, sync, themes and shortcuts, user agents and drag to scroll. They need Playwright:
npm installnpx playwright install chromiumnpm run e2eSet VIEWPORT_E2E_CHANNEL=msedge to use an installed Edge instead. Both suites run in CI on every push. After changes, also run the manual checklist in CONTRIBUTING.md. docs/demo.html is a fictional site that covers the tricky cases: a sticky header, a horizontal scroller, a phone-only fixed bar and a responsive grid.
Issues and pull requests are welcome. Read CONTRIBUTING.md first. To report a security issue, follow SECURITY.md.


