Skip to main content
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

ApproachBest for
srcset + sizes (responsive guide)Predictable layouts, <ConvertlyImage>, most React/Next apps
ch=Width,DprFluid 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)

  1. Open chrome://flags/#enable-experimental-web-platform-features or ensure Client Hints are enabled for your origin.
  2. Serve your page over HTTPS (or localhost).
  3. 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 paramHeader readEffect
ch=WidthSec-CH-WidthOutput width in CSS pixels (× DPR when Dpr is also enabled)
ch=DprSec-CH-DPR or DPRDevice pixel ratio multiplier
ch=Width,DprBothRecommended combination
ch=Viewport-WidthSec-CH-Viewport-WidthFull 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.