---
slug: "aws-amplify-hosting-request-headers"
title: "All Request Headers Available in AWS Amplify Hosting (Geo / ASN / Device)"
description: "AWS Amplify Hosting passes CloudFront geo headers (country, region, ASN, device type, postal code, lat/long) to SSR. How to access them in SvelteKit."
url: "https://www.ytyng.com/en/blog/aws-amplify-hosting-request-headers"
publish_date: "2026-05-22T14:08:05.641Z"
created: "2026-05-22T14:08:05.650Z"
updated: "2026-05-22T16:54:03.614Z"
categories: []
keywords: ""
featured_image_url: "https://media.ytyng.com/resize/20260522/e3553b96603547ed89beb03f5092c4e1.png.webp?width=768"
has_video: false
has_music: false
video_urls: []
music_urls: []
lang: "en"
---

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

## 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)](https://github.com/aws-amplify/amplify-hosting/issues/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

```ts
// 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

```ts
// 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)

```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.

```ts
// 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:

```ts
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

- [AWS CloudFront: Add CloudFront request headers](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-cloudfront-headers.html)
- [SSR request loses original headers · Issue #2161 · aws-amplify/amplify-hosting](https://github.com/aws-amplify/amplify-hosting/issues/2161) (resolved by now)
- [amplify-adapter (for SvelteKit)](https://github.com/gzimbron/amplify-adapter)

