Client Hints let the browser tell the CDN how wide an image is displayed and the device pixel ratio — so you can omit a fixed w= and still get correctly sized bytes. Convertly reads Sec-CH-Width, Sec-CH-DPR, and legacy DPR when you pass ch=Width,Dpr on the URL.
Reference: Format & delivery → Client hints.
Client Hints require HTTPS and a browser that sends the hints (Chrome, Edge, and Chromium-based browsers are the main adopters). Always provide a fallback width in src or a w= default for browsers that do not send hints.
When to use Client Hints vs srcset
| Approach | Best for |
|---|
srcset + sizes (responsive guide) | Predictable layouts, <ConvertlyImage>, most React/Next apps |
ch=Width,Dpr | Fluid layouts, unknown slot widths — one URL adapts to viewport width |
You can combine both: fixed breakpoints in <picture> and Client Hints on individual hero images.
Basic CDN URL
Omit w and opt in to hints:
<img
src="https://cdn.convertly.sh/{namespace}/{fileId}?ch=Width,Dpr&fit=cover&h=600&format=auto"
alt="Hero"
/>
Convertly multiplies Sec-CH-Width (CSS pixels) by dpr (from Sec-CH-DPR or the dpr query param) to derive output width, then applies fit=cover with your h=600.
See the before/after example in Format & delivery.
Enable hints in the browser
Chrome (local testing)
- Open
chrome://flags/#enable-experimental-web-platform-features or ensure Client Hints are enabled for your origin.
- Serve your page over HTTPS (or
localhost).
- Add a
<meta> tag or Accept-CH response header so the browser knows which hints to send on the next navigation:
<meta http-equiv="Accept-CH" content="Width, DPR, Viewport-Width" />
Or from your origin (Next.js middleware, nginx, or your CDN’s response headers):
Accept-CH: Width, DPR, Viewport-Width
CDN image requests
Hints apply to the document that loads the <img>. The browser attaches Sec-CH-* headers to subresource requests (your Convertly CDN URLs) when the hint was negotiated for the top-level page.
Next.js example
// middleware.ts — negotiate hints for all pages
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const response = NextResponse.next();
response.headers.set("Accept-CH", "Width, DPR, Viewport-Width");
return response;
}
import { createConvertlyCdn } from "@convertly-sh/image";
const cdn = createConvertlyCdn({ namespace: process.env.NEXT_PUBLIC_CONVERTLY_CDN_NAMESPACE! });
export function FluidHero({ fileId }: { fileId: string }) {
return (
<img
src={cdn.url(fileId, { ch: "Width,Dpr", h: 600, fit: "cover" })}
alt="Hero"
style={{ width: "100%", height: "auto" }}
/>
);
}
Supported hint parameters
| URL param | Header read | Effect |
|---|
ch=Width | Sec-CH-Width | Output width in CSS pixels (× DPR when Dpr is also enabled) |
ch=Dpr | Sec-CH-DPR or DPR | Device pixel ratio multiplier |
ch=Width,Dpr | Both | Recommended combination |
ch=Viewport-Width | Sec-CH-Viewport-Width | Full viewport width when slot width is unknown |
If no hint arrives, set an explicit fallback: ?w=1200&ch=Width,Dpr uses 1200 when Sec-CH-Width is absent.
Caching behaviour
Client Hint variants are cached separately. Convertly sets Vary appropriately so AVIF/WebP negotiation and hint-based widths do not collide at the edge. See How caching works.