Skip to content
PN Scripts

Development

Full-page screenshots in Firefox, and a frame that makes them fit a store page or a link preview

  • PN Scripts
  • 9 min read

A screenshot of a website is one of the most common pictures in a portfolio, a store listing, a slide or a link preview, and also one of the most often badly made: cut off in the wrong place, blurry, with a scroll bar and a cookie banner, stretched into a size it was never meant for. Firefox can take a picture of the whole length of a page without any add-on, in three different ways. This guide shows all three, what goes wrong on long pages, and how to put the result in a simple frame at the exact size a link preview or a store page expects.

#Three ways to capture the whole page

From the menu. Right-click an empty part of the page and choose Take Screenshot, or press Ctrl+Shift+S (Cmd+Shift+S on a Mac). Firefox offers Save full page and Save visible, or lets you drag a region. This is the quickest way for a single picture.

From the Web Console. Open the developer tools (F12), go to the Console and type :screenshot --fullpage. The console version takes options the menu does not: --dpr 2 captures at twice the pixel density, so text stays sharp when the picture is scaled down; --file with a name chooses the file name; --clipboard copies the picture instead of saving it.

From the command line. Firefox can run without a window and save a page straight to a file, which is useful for capturing many pages or the same page every week:

mkdir -p ~/shots/profile
firefox --headless --profile ~/shots/profile --screenshot ~/shots/page.png --window-size=1280 https://example.com/

The width matters more than you might expect. With --window-size=1280 alone, Firefox lays the page out 1280 pixels wide and saves its full length; with --window-size=1280,800 it saves only the first 800 pixels, like a visible screenshot; with no size at all it uses a width of 1366. The separate profile folder lets the command run while your normal Firefox is open. On Ubuntu, where Firefox comes as a snap package, keep the profile and the output in your home folder: the snap could not use a profile folder in /tmp when we tried.

#What goes wrong on long pages

  • Images that load late. Many sites load images only when you scroll near them, so a full-page capture taken straight away has empty boxes at the bottom. Scroll to the end and back before you capture, or wait a few seconds.
  • Things that follow you. A header that sticks to the top and a chat button that sticks to a corner appear once, where they are when the picture is taken. Tools that scroll and stitch several screenshots together instead repeat them on every screen; Firefox draws the page in one piece and avoids that.
  • Banners and pop-ups. Accept or close the cookie banner and any newsletter pop-up first. A screenshot meant for a portfolio should show the site, not the consent dialog.
  • The scroll bar. A headless capture of a page that scrolls keeps an empty strip about 12 pixels wide on the right where the scroll bar would be. Cut it off before you use the picture.
  • Very long pages. A page of tens of thousands of pixels becomes an enormous image that nobody can read when it is scaled to fit a slide. For a portfolio, the top of the page plus one or two chosen sections usually tells more than the whole thing.

#Pick the size before you frame

The picture will be shown at a fixed shape, and it is better to design for it than to let a website crop it for you:

  • 1200 × 630 for link previews when the page is shared in a chat or on social media (the image in the page's og:image tag);
  • 1080 × 1080 or 1080 × 1350 for a post;
  • 1920 × 1080 for a slide or a video;
  • 1600 × 900 as a general 16:9 size for a store page or a blog, unless the store names its own size, in which case use that.

Keep text readable at the size the picture is actually shown. A whole page squeezed into 1200 × 630 is a texture, not a screenshot; the top part of the page at full width is something people recognise.

#A frame in a few lines of Python

A plain window frame on a soft background makes a screenshot look finished and separates it from the page around it. This script, with the Pillow library, takes a capture, cuts off the scroll bar strip if you give its width, scales the page to the frame, keeps the top, and draws a light title bar, round corners and a shadow on a gradient, at 1200 × 630:

import sys
from PIL import Image, ImageDraw, ImageFilter

W, H = 1200, 630            # a link preview; 1600x900 for a store page
PAD, BAR, RADIUS = 60, 36, 14

shot = Image.open(sys.argv[1]).convert("RGB")
cut = int(sys.argv[3]) if len(sys.argv) > 3 else 0   # the scroll bar strip a headless capture keeps
shot = shot.crop((0, 0, shot.width - cut, shot.height))
inner_w = W - 2 * PAD
inner_h = H - 2 * PAD - BAR
# Scale to the frame's width and keep the top of the page: that is what people recognise.
shot = shot.resize((inner_w, round(shot.height * inner_w / shot.width)), Image.LANCZOS)
shot = shot.crop((0, 0, inner_w, min(inner_h, shot.height)))

# Background: a vertical gradient between two colours.
top, bottom = (31, 41, 79), (22, 120, 118)
bg = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(bg)
for y in range(H):
    k = y / (H - 1)
    draw.line([(0, y), (W, y)], fill=tuple(round(a + (b - a) * k) for a, b in zip(top, bottom)))

# The window: a light title bar with three dots, the page under it, round corners.
win = Image.new("RGB", (inner_w, BAR + shot.height), (236, 238, 242))
win.paste(shot, (0, BAR))
wd = ImageDraw.Draw(win)
for i, colour in enumerate([(237, 106, 94), (245, 191, 79), (98, 197, 84)]):
    cx = 22 + i * 20
    wd.ellipse([cx - 6, BAR // 2 - 6, cx + 6, BAR // 2 + 6], fill=colour)
mask = Image.new("L", win.size, 0)
ImageDraw.Draw(mask).rounded_rectangle([0, 0, win.width - 1, win.height - 1], RADIUS, fill=255)

# A soft shadow under the window, then the window itself.
shadow = Image.new("L", (W, H), 0)
ImageDraw.Draw(shadow).rounded_rectangle([PAD, PAD + 12, PAD + win.width, PAD + 12 + win.height], RADIUS, fill=110)
bg.paste((0, 0, 0), (0, 0), shadow.filter(ImageFilter.GaussianBlur(18)))
bg.paste(win, (PAD, PAD), mask)
bg.save(sys.argv[2], quality=90)
print(bg.size, "window", win.size)

Run it as python frame.py page.png framed.jpg 12. Change W and H for the other sizes, and the two colours for your brand. Save as PNG when the picture is mostly text and flat colour, and as JPEG or WebP when it holds photos; a JPEG of a text-heavy page shows blurry edges around the letters.

#Device frames

A phone or laptop around the screenshot says "this works on mobile" faster than words, but draw plain devices. Pictures of a specific branded phone or laptop raise trademark questions in advertising, and they date quickly. A phone frame also needs the page captured at a phone width (around 390 pixels, with a matching device pixel ratio) rather than a desktop page squeezed into a phone shape.

#An add-on that does all of this

We made Ramka, a Firefox extension that captures the visible part or the whole page and opens it in an editor with a browser window, a plain phone, tablet or laptop frame, or no frame, on a gradient, a colour, a blurred copy of the picture or a transparent background. It sizes the result for link previews, posts, slides and store pages, saves PNG, JPEG or WebP, copies to the clipboard, and frames pictures you already have. It draws the whole page at once, sharp on high-density screens, up to 16384 CSS pixels tall; longer pages are cut and the editor says so. Firefox does not allow pictures of its own pages, such as about: pages and the add-ons site. Ramka needs Firefox 142 or newer, collects no data and makes no network requests. It was checked with automated tests, Mozilla's add-ons linter and a run in a real headless Firefox; it is not yet signed by Mozilla, so for now it installs as a temporary add-on. It is listed as Coming soon.

#Frequently asked questions

How do I take a full-page screenshot in Firefox without an add-on?

Right-click the page, choose Take Screenshot and then Save full page, or type :screenshot --fullpage in the Web Console of the developer tools.

Why are images missing at the bottom of my full-page screenshot?

The site loads images only when you scroll near them. Scroll to the end of the page and back, wait a moment, then capture.

What size should a link preview image be?

1200 × 630 pixels is the size most link previews use. Keep the important part away from the edges, because some apps crop the picture to a square or a narrower shape.

Can I take screenshots of many pages automatically?

Yes. Run Firefox headless from the command line with --screenshot for each address, using a separate profile folder, and frame the files with a script afterwards.

#Sources

Keep reading

Keep reading

Comments

Comments

Be the first to leave a comment.

Leave a comment

Next step

pnscripts.com/contact

Talk to the team

Ask about an article, or tell us about a project you want built. We reply within one business day.

Write to us

The PN Scripts family

Other PN Scripts sites

Hosting, games and the blog each have their own site, run by the same company.

  • pnscripts.com

    PN Scripts

    Software engineering

    Custom web, mobile, API and game development, plus our open-source products and plugins.

  • games.pnscripts.com

    Games

    Games and game servers

    The home for PN Scripts games: free browser games you can play right now, with game servers coming soon.

  • hosting.pnscripts.com

    Hosting

    Hosting and infrastructure

    Shared hosting, KVM VPS, dedicated servers and domains, from the same company that builds your project.

  • blog.pnscripts.com

    Blog

    Articles and field notes

    Practical articles on software development, hosting, open source and games, written by the people who build them.

    You are here