All Request Headers Available in AWS Amplify Hosting (Geo / ASN / Device)

2026-05-22 14:08 (23 days ago)
Header Buffet
Play a song themed on this article

TL;DR

The request handlers in AWS Amplify Hosting's SSR receive a wealth of user information that CloudFront adds to every incoming request.

Without integrating MaxMind, geoip-lite, or any other GeoIP library, you can get the country, region, city, postal code, latitude/longitude, ASN, and device type out of the box.

All the headers that actually arrive

I dumped the full contents of request.headers in a production deployment and confirmed the following:

Geo (location) headers

Header Example value Meaning
cloudfront-viewer-country JP ISO 3166-1 alpha-2 country code
cloudfront-viewer-country-name Japan Country name (English)
cloudfront-viewer-country-region 13 ISO 3166-2 subdivision code (Tokyo)
cloudfront-viewer-country-region-name Tokyo Region / state name
cloudfront-viewer-city Matsubara City name
cloudfront-viewer-postal-code 156-0041 Postal code
cloudfront-viewer-latitude 35.xxxxxx Latitude
cloudfront-viewer-longitude 139.xxxxxx Longitude
cloudfront-viewer-time-zone Asia/Tokyo Time zone

You even get the postal code and latitude / longitude. Treat these with care from a privacy perspective.

The city name was not actually the city I was accessing from — it was off by about 3 km.

Network headers

Header Example value Meaning
cloudfront-viewer-asn 25XX AS number
cloudfront-viewer-address 203.0.xxx.xxx:53xxx Client IP and port
cloudfront-viewer-tls TLSv1.3:TLS_AES_128_GCM_SHA256:connectionReused TLS version and cipher suite
cloudfront-viewer-http-version 3.0 HTTP version
cloudfront-forwarded-proto https Client-side protocol
x-forwarded-for 203.0.xxx.xxx, 64.252.xxx.xxx List of IPs along the proxy path
x-forwarded-host example.com Client-side Host
x-forwarded-port 443 Client-side port
x-forwarded-proto https Client-side protocol
via 3.0 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront) CloudFront pass-through information

Some of the values above have been partially anonymized.

Getting the ASN is a nice bonus. With it, you can classify access like "came from a specific ISP" or "came from an AWS data center."

Device type

Header Example value
cloudfront-is-desktop-viewer true
cloudfront-is-mobile-viewer false
cloudfront-is-tablet-viewer false
cloudfront-is-smarttv-viewer false
cloudfront-is-ios-viewer false
cloudfront-is-android-viewer false

You can distinguish desktop / mobile / tablet / TV without parsing the User-Agent yourself — CloudFront looks at the UA and gives you the result.

AWS internal trace headers

Header Purpose
x-amzn-trace-id Trace ID for X-Ray and similar
x-amz-cf-id CloudFront request ID (needed when contacting AWS support)

Original browser headers (not overwritten!)

Header Example value
user-agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ... Chrome/146.0.0.0 ...
accept-language ja,en-US;q=0.9,en;q=0.8
host example.com

Back around 2022 there was a report on GitHub issue (#2161) that "Amplify SSR replaces user-agent with Amazon CloudFront", but today the original browser UA is preserved. You can extract details with libraries like ua-parser-js.

How to read them in SvelteKit SSR

The request: Request object passed into load functions and actions handlers exposes .headers — just read them from there.

Example: load function

// src/routes/+page.server.ts
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ request }) => {
  const headers = request.headers;

  const country = headers.get('cloudfront-viewer-country-name'); // 'Japan'
  const region = headers.get('cloudfront-viewer-country-region-name'); // 'Tokyo'
  const asn = headers.get('cloudfront-viewer-asn'); // '25XX'

  return {
    location: { country, region, asn }
  };
};

Example: action handler

// src/routes/+page.server.ts
import type { Actions } from './$types';

export const actions: Actions = {
  default: async ({ request }) => {
    const country = request.headers.get('cloudfront-viewer-country');
    // ...
  }
};

Example: API endpoint (+server.ts)

// src/routes/api/some/+server.ts
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ request }) => {
  const country = request.headers.get('cloudfront-viewer-country');
  return new Response(JSON.stringify({ country }));
};

Wrap it up as a utility

In a real project, it's convenient to extract this into a utility function.

// src/lib/server/geo.ts
export type DeviceType = 'desktop' | 'mobile' | 'tablet' | 'tv' | undefined;

export interface GeoInfo {
  country?: string;
  countryCode?: string;
  region?: string;
  asn?: number;
  deviceType?: DeviceType;
}

export function extractGeoInfo(headers: Headers): GeoInfo {
  const asnRaw = headers.get('cloudfront-viewer-asn');
  const asn = asnRaw ? parseInt(asnRaw, 10) : undefined;

  let deviceType: DeviceType;
  if (headers.get('cloudfront-is-tablet-viewer') === 'true') {
    deviceType = 'tablet';
  } else if (headers.get('cloudfront-is-mobile-viewer') === 'true') {
    deviceType = 'mobile';
  } else if (headers.get('cloudfront-is-smarttv-viewer') === 'true') {
    deviceType = 'tv';
  } else if (headers.get('cloudfront-is-desktop-viewer') === 'true') {
    deviceType = 'desktop';
  }

  return {
    country: headers.get('cloudfront-viewer-country-name') || undefined,
    countryCode: headers.get('cloudfront-viewer-country') || undefined,
    region: headers.get('cloudfront-viewer-country-region-name') || undefined,
    asn: asn !== undefined && Number.isFinite(asn) ? asn : undefined,
    deviceType
  };
}

Caller side:

import { extractGeoInfo } from '$lib/server/geo';

export const load: PageServerLoad = async ({ request }) => {
  const geo = extractGeoInfo(request.headers);
  console.log(geo);
  // { country: 'Japan', countryCode: 'JP', region: 'Tokyo', asn: 25XX, deviceType: 'desktop' }
};

References

Please rate this article (No signup or login required)
Current rating: 5.0 (1)
The author runs the application development company Cyberneura.
We look forward to discussing your development needs.

Categories

Archive