Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Use Sharp’s composite() method to place a transparent text layer over your screenshot, then encode the result with png(), jpeg(), or another output method. The most portable approach is to create the watermark as an SVG buffer, which gives you control over fonts, color, opacity, background shapes, and layout without creating a separate image file.
This guide shows a complete Node.js implementation, exact and semantic positioning, generated-text alternatives, batch processing, format selection, troubleshooting, and an API option when you would rather not configure a browser capture pipeline.
What you need
- Node.js 20.9.0 or later, or another runtime compatible with Sharp’s Node-API v9 requirement.
- A screenshot file such as
screenshot.png. - A project using ECMAScript modules or an equivalent CommonJS import.
Install Sharp with:
npm install sharp
Sharp uses the host system’s font configuration when rendering SVG and generated text. A font named in your watermark must therefore be installed or otherwise available to the machine running the script.
Minimal watermark: transparent SVG over a screenshot
Create watermark.mjs:
import sharp from 'sharp';
const watermark = Buffer.from(`
<svg width="420" height="90">
<text x="16" y="56" font-family="Arial, sans-serif" font-size="30"
fill="white" fill-opacity="0.72">© Example</text>
</svg>
`);
await sharp('screenshot.png')
.composite([{ input: watermark, gravity: 'southeast' }])
.png()
.toFile('screenshot-watermarked.png');
Run it with:
node watermark.mjs
The output is a new PNG named screenshot-watermarked.png. The source file is not modified. The SVG has a transparent background, so only the text is composited. gravity: 'southeast' places the overlay in the bottom-right corner.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minute#1 Best Overall
How Sharp compositing works
sharp(input) creates a processing pipeline for the base image. composite(images) then places one or more overlays on the processed image. Every overlay must be the same size as or smaller than that processed image.
An overlay object can contain an image buffer, a file path, or generated input, together with placement and blending options. You can pass several overlay objects in one array, allowing a logo, copyright notice, and a timestamp to be added in one operation.
Semantic placement with gravity
northwest: top-left.north: centered at the top.northeast: top-right.west,centre, oreast: vertically centered.southwest: bottom-left.south: centered at the bottom.southeast: bottom-right.
Gravity is useful when the screenshot dimensions vary. The watermark keeps its relationship to the edge instead of requiring you to calculate coordinates for every image.
Exact pixel offsets
For a fixed margin or a design specification, supply integer top and left values:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →await sharp('screenshot.png')
.composite([
{ input: watermark, top: 20, left: 20 }
])
.png()
.toFile('screenshot-top-left.png');
When both top and left are supplied, they take precedence over gravity. Use offsets when you need a watermark exactly 20 pixels from two edges, regardless of its semantic corner.
Build a more readable watermark with an SVG background
White text can disappear over a pale page, while black text can disappear over a dark page. Add a translucent rectangle behind the text:
Rank #2
import sharp from 'sharp';
const watermark = Buffer.from(`
<svg width="460" height="104" viewBox="0 0 460 104">
<rect x="0" y="0" width="460" height="104" rx="12"
fill="#000000" fill-opacity="0.55" />
<text x="22" y="66" font-family="Arial, sans-serif"
font-size="30" fill="#ffffff">© Example Studio</text>
</svg>
`);
await sharp('screenshot.png')
.composite([{ input: watermark, gravity: 'southeast' }])
.png()
.toFile('screenshot-watermarked.png');
The SVG dimensions are part of the overlay. Keep them comfortably within the screenshot dimensions; an overlay larger than the processed base image cannot be composited as intended.
Use Sharp’s generated-text input instead of SVG
Sharp also supports text generated from an input.text object. This is convenient when you only need text and do not want to write SVG markup. The text input supports UTF-8 content, font selection, width and height limits, alignment, DPI, RGBA output, and line spacing.
Recommended Free Tools
import sharp from 'sharp';
const textLayer = {
text: {
text: '© Example Studio',
font: 'Arial',
fontSize: 30,
rgba: true,
align: 'center'
},
width: 360,
height: 70,
channels: 4
};
await sharp('screenshot.png')
.composite([
{ input: textLayer, gravity: 'southeast' }
])
.png()
.toFile('screenshot-text-input.png');
Choose generated text for a straightforward label. Choose SVG when you need a backing rectangle, rounded corners, multiple text runs, custom shapes, or styling that is easier to express declaratively.
Resize or crop before adding the watermark
Geometry operations in the same Sharp pipeline—such as resize, rotate, flip, flop, and extract—are applied to the input image before composition. Put those operations before composite() so the watermark is positioned on the final dimensions:
import sharp from 'sharp';
const watermark = Buffer.from(`
<svg width="420" height="90">
<text x="16" y="56" font-family="Arial" font-size="30"
fill="white" fill-opacity="0.72">© Example</text>
</svg>
`);
await sharp('screenshot.png')
.resize({ width: 1600, withoutEnlargement: true })
.rotate(2)
.composite([{ input: watermark, gravity: 'southeast' }])
.webp({ quality: 88 })
.toFile('screenshot-watermarked.webp');
If you composite first and then resize, the watermark becomes part of the pixels being resized. Its size, sharpness, and margin will change with the image, which is usually not what you want.
Save as PNG, JPEG, WebP, or another format
Select the encoder explicitly at the end of the pipeline:
Rank #3
.png()preserves sharp text and interface edges without lossy compression..jpeg({ quality: 85 })is useful when a smaller photographic file is more important than pixel-perfect UI edges..webp({ quality: 88 })provides a modern compressed image format.- Sharp also supports AVIF, TIFF, GIF, and raw pixel output.
await sharp('screenshot.png')
.composite([{ input: watermark, gravity: 'southeast' }])
.jpeg({ quality: 85, progressive: true })
.toFile('screenshot-watermarked.jpg');
If you do not select a format, Sharp normally preserves the input format; SVG input is an exception and is written as PNG.
Watermark several screenshots
Construct the watermark once and reuse it for each input. This keeps the design consistent; measure your own workload before assuming a particular throughput.
import sharp from 'sharp';
const watermark = Buffer.from(`
<svg width="420" height="90">
<rect width="420" height="90" rx="10" fill="#000" fill-opacity="0.45" />
<text x="16" y="56" font-family="Arial" font-size="30" fill="#fff">
© Example
</text>
</svg>
`);
const files = ['one.png', 'two.png', 'three.png'];
await Promise.all(files.map((file) =>
sharp(file)
.composite([{ input: watermark, gravity: 'southeast' }])
.png()
.toFile(file.replace(/.png$/i, '-watermarked.png'))
));
For very large batches, limit concurrency to match available CPU and memory rather than launching unlimited image operations at once.
Common errors and fixes
“Input image exceeds overlay dimensions” or a missing watermark
Check the screenshot dimensions and the SVG or text-layer dimensions. An overlay must not be larger than the processed image. Reduce the SVG width and height, resize the base first, or calculate a smaller overlay for narrow screenshots.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Text is clipped
Increase the SVG canvas height and width, move the baseline inward, or set a sufficient width and height on generated text input. SVG text uses a baseline: a y value too close to the top or bottom can clip glyphs and accents.
The watermark is unreadable
Use a color with stronger contrast, increase or decrease opacity, add a translucent backing rectangle, or move the label to a less visually busy corner. A fixed white label is not reliably legible on arbitrary screenshots.
Rank #4
The font changes between machines
Install the same font on every host, or choose a broadly available fallback such as a generic sans-serif family. SVG and text rendering use the host’s font discovery configuration, so a font name in code does not install that font.
The output is unexpectedly huge or blurry
Choose the output encoder deliberately. PNG is lossless but can be large; JPEG and WebP trade some fidelity for size. Avoid repeatedly decoding and re-encoding the same image in separate steps when one Sharp pipeline can perform the work.
Rotation or cropping seems to use the wrong coordinates
Place rotate or extract before composite(). Composition coordinates refer to the processed base image, not the original file’s dimensions.
Or skip the browser setup
If you still need to obtain the screenshot, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. It accepts consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and whether it was billed.
After downloading the clean image, you can pass it through the Sharp code above. The API call itself can be made with cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
See the ScreenshotNeo documentation for parameters and response details. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. There is a free allowance of 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is included on every plan. Create a free ScreenshotNeo account.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Practical design decisions
Pick a placement that does not hide content
Bottom-right is conventional, but browser screenshots often contain controls or cookie notices there. Inspect the target layout and use a corner with stable empty space. For automated jobs, keep the placement configurable.
Keep the watermark predictable
Use a fixed SVG canvas, explicit font size, and explicit opacity. If source screenshots vary greatly in width, generate the SVG dimensions from the source metadata or use a smaller design that fits the narrowest expected image.
Keep originals and verify output
Write to a separate filename or directory, check the returned promise for errors, and inspect the resulting dimensions and format when the files are consumed by another system. Do not overwrite originals until the output has passed your visual and automated checks.
Frequently Asked Questions
Can I watermark a screenshot without saving a separate overlay file?
Yes. Pass an SVG string or generated-text object as a buffer or input directly to Sharp’s composite() method.
Which format should I use for a screenshot watermark?
Use PNG when crisp interface text and edges are the priority. Choose JPEG or WebP when a smaller file is more important and some compression is acceptable.
Can one Sharp call add multiple watermarks?
Yes. Provide multiple overlay objects in the array passed to composite(), such as a logo and a copyright label.
Quick Recap
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.

