What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Puppeteer to render your local HTML template in a browser page sized to the image you need, wait until its content and assets are ready, then save the rendered page with page.screenshot(). The key to reliable output is treating the template as a fixed-size design and defining an explicit readiness condition before capture.

Build the template around the image canvas

Create the HTML and CSS as the visual source of truth. Give the design a fixed width and height matching the dimensions required by your publishing destination, and verify that destination’s current guidance when exact Open Graph dimensions matter; there is no single dimension established here for every platform.

Keep important text and artwork within the canvas, and use CSS layout and typography to control the composition. If your template uses local images, fonts, or other assets, make sure the page can resolve them—for example, by using file URLs or embedding the assets. Choose one specific readiness condition for the design rather than assuming that the initial HTML assignment means every asynchronous asset has finished loading.

Render local HTML and save a screenshot

The example below reads a local HTML file, sets the viewport before assigning the markup, waits for a template-defined ready marker, and writes a PNG. It uses the Puppeteer Page APIs documented at https://pptr.dev/api/puppeteer.page and the HTML assignment method documented at https://pptr.dev/api/puppeteer.page.setcontent. Use documentation matching the version installed in your project because API behavior can vary by version.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Save this as generate-og.cjs alongside og-template.html, then run it in a project where Puppeteer is installed:

const fs = require('node:fs/promises');
const puppeteer = require('puppeteer');

const WIDTH = 1200;
const HEIGHT = 630;

async function main() {
  const html = await fs.readFile('./og-template.html', 'utf8');
  const browser = await puppeteer.launch();

  try {
    const page = await browser.newPage();
    await page.setViewport({ width: WIDTH, height: HEIGHT, deviceScaleFactor: 1 });
    await page.setContent(html, { waitUntil: 'load' });

    // Add this element to the template only after its content is ready:
    await page.waitForSelector('[data-og-ready="true"]');

    await page.screenshot({ path: './og-image.png', type: 'png' });
  } finally {
    await browser.close();
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

The template needs to include the marker when it is ready, such as <div data-og-ready="true">. For a purely static template, the marker can be present in the initial markup. If JavaScript fills in content or loads assets, add or expose the marker only after the work your image depends on is complete. The selector-wait pattern is also shown in Puppeteer’s screenshots guide.

Capture the whole page or a single element

For a fixed-size canvas, use page.screenshot() as above. If the design is a specific element within a larger page, wait for its selector, obtain the element handle, and capture that element with ElementHandle.screenshot():

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
const card = await page.waitForSelector('#og-card');
if (!card) throw new Error('Could not find #og-card');
await card.screenshot({ path: './og-card.png', type: 'png' });

Element capture is useful when the target’s bounds—not the page viewport—should define the output. The Puppeteer guide demonstrates both page and element screenshots.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the output format

Set the output filename extension to match the format you request. Puppeteer’s screenshot guide demonstrates saving a capture to a path; consult the API documentation for the installed version when choosing screenshot options. The example explicitly requests PNG. If your publishing workflow expects another format, change the screenshot type and filename together.

Make rendering repeatable

Set the viewport before rendering

Set the target width and height before calling setContent() or navigating. The viewport controls the page’s rendering area and therefore affects line wrapping, responsive CSS, and element dimensions. Puppeteer notes that changing the viewport can reload a page in some cases, so configure it up front rather than resizing after the template is laid out.

Wait for what the design actually needs

waitUntil: 'load' waits for the page load event, but it does not by itself define whether every custom font, image, or application-rendered element is ready for your particular design. Use a selector or a readiness signal that represents the finished composition. A fixed delay can be used when a template has a known delay, but it is less reliable than signaling readiness when the relevant work completes.

For fonts and images, make the template’s ready marker depend on the assets the design requires. Avoid treating network idleness as a universal guarantee: the relevant condition is whether this template’s visible output is complete, not simply whether network activity has paused.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If you want a screenshot API rather than managing a local Puppeteer browser, ScreenshotNeo accepts a URL in one GET request and returns an image or PDF. This is an alternative for capturing a page available at a URL; the Puppeteer workflow above remains the direct method for rendering an in-memory local HTML string.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Example cURL request, with the target URL changed to your hosted template:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. It also offers an MCP server for AI agents, and includes 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000.

Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month without a card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshoot missing or incorrect output

  • The screenshot is blank or incomplete: Check that the HTML was read successfully and that the readiness selector appears only when the intended content is present. If the template uses JavaScript, confirm it runs in the page context.
  • Images or fonts are missing: Verify that asset URLs resolve from the page created by setContent(). Relative paths may not resolve as they do when opening a file directly; use accessible file URLs or embed assets, then make readiness depend on them.
  • The layout has the wrong dimensions or wraps differently: Set the intended viewport before assigning content, and check the template’s fixed dimensions and responsive CSS. Confirm the target platform’s current image guidance separately.
  • The script exits before writing the file: Inspect the error printed by the catch handler. The finally block closes the browser even after a capture failure; address the reported launch, page, selector, or file-path error before rerunning.
  • The selector wait never completes: Ensure the selector exists in the template and that any script responsible for setting it executes. If no asynchronous work is needed, include the marker in the initial HTML.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and operating cost

This approach launches a browser, renders a page, and writes a local file, so it fits build scripts and controlled rendering jobs where you can manage the browser lifecycle. Reuse a browser process for multiple images in a job when appropriate, while isolating pages and closing the browser when the job ends. For repeatable output, keep the viewport, template inputs, asset availability, and readiness condition consistent.

No performance benchmark or per-image cost is established here. The method uses your own Puppeteer runtime and infrastructure; account for browser execution and asset-loading time in your build or service. Consult the Puppeteer getting-started guide for browser launch and page setup appropriate to your installed version.

Frequently Asked Questions

Can I use this approach with a template stored as a string?

Yes. Pass the string directly to page.setContent() instead of reading it from a file.

Does the example guarantee the same result in every Puppeteer version?

No. Use the API documentation that matches your installed Puppeteer version and verify the screenshot options used by your project.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.