Skip to content

A free API for the sun and the moon.

Sunrise, sunset, twilight, golden hour and moon data for any point on Earth. One GET request, no key, no signup.

Try it

GEThttps://api.sunrisesunset.io/json?lat=38.9&lng=-77
Request
fetch("https://api.sunrisesunset.io/json?lat=38.9&lng=-77")
  .then(r => r.json())
  .then(data => console.log(data.results.sunrise));
curl "https://api.sunrisesunset.io/json?lat=38.9&lng=-77"
Cost
Free, with a link back to sunrisesunset.io
Auth
None. GET only, CORS enabled
Range
Up to 365 days per request
Latency
Under 50 ms at P99, from Cloudflare's edge
Response200 OK
{
  "results": {
    "date": "2026-06-21",
    "sunrise": "5:41:58 AM",
    "sunset": "8:38:05 PM",
    "first_light": "3:42:23 AM",
    "last_light": "10:37:39 PM",
    "dawn": "5:09:48 AM",
    "dusk": "9:10:15 PM",
    "solar_noon": "1:10:02 PM",
    "golden_hour": "7:58:03 PM",
    "day_length": "14:56:06",
    "nautical_twilight_begin": "4:29:11 AM",
    "nautical_twilight_end": "9:50:51 PM",
    "timezone": "America/New_York",
    "utc_offset": -240,
    "sun_altitude": 74.54,
    "sun_azimuth": 180,
    "sunrise_azimuth": 58.3,
    "sunset_azimuth": 301.7,
    "moonrise": "1:01:52 PM",
    "moonset": "12:41:20 AM",
    "moon_illumination": 47.57,
    "moon_phase": "First Quarter",
    "moon_phase_value": 0.24,
    "moon_always_up": false,
    "moon_always_down": false,
    "elevation": 26,
    "sun_status": "normal",
    "golden_hour_morning": {
      "begin": "5:22:29 AM",
      "end": "6:22:00 AM"
    },
    "golden_hour_evening": {
      "begin": "7:58:03 PM",
      "end": "8:57:33 PM"
    },
    "blue_hour_morning": {
      "begin": "5:09:48 AM",
      "end": "5:22:29 AM"
    },
    "blue_hour_evening": {
      "begin": "8:57:33 PM",
      "end": "9:10:15 PM"
    }
  },
  "status": "OK",
  "tzid": "America/New_York"
}

Try it

Runs against the live API from your browser.

GEThttps://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873
Ready
Send a request to see the response here.

Examples

Parameters

Query-string values on a single GET request.

latnumberrequired

Latitude in decimal degrees.

Example 38.907192

lngnumberrequired

Longitude in decimal degrees.

Example -77.036873

datestring

Date to query. ISO YYYY-MM-DD, or a relative word like "today" or "tomorrow". Defaults to today in the location's timezone.

Example 2026-06-21

date_startstring

Start of a date range (inclusive). Must be paired with date_end. Up to 365 days.

date_endstring

End of a date range (inclusive). Returns an array of daily results instead of a single object.

timezoneIANA tz

Return times in this timezone. Defaults to the location's IANA timezone resolved from lat/lng. An invalid value still returns data, with status INVALID_TZID and the detected zone.

Default autoExample America/New_York

time_formatenum

Format of all time fields. One of 12, 24, military, unix. Unix timestamps are always UTC.

Default 12

formatted0 | 1

Set to 0 to receive times in ISO 8601 format and day_length in seconds.

Default 1

elevationnumber | false

Elevation override in meters. By default, auto-detected from terrain via ETOPO1. Pass false to compute at sea level. Higher elevation pushes sunrise earlier and sunset later.

Default auto

callbackstring

JSONP callback function name. Returns application/javascript wrapped in your callback when present.

Response fields

Wrapped in { results, status, tzid }. results is one object, or an array when you pass a date range.

Sun

sunrise
time
Sunrise time.
sunset
time
Sunset time.
solar_noon
time
Sun at its highest point.
day_length
H:MM:SS | seconds
Length of daylight (seconds if formatted=0).
sunrise_azimuth
degrees
Compass bearing where the sun rises.
sunset_azimuth
degrees
Compass bearing where the sun sets.
sun_altitude
degrees
Sun altitude at solar noon.
sun_azimuth
degrees
Sun azimuth at solar noon (N = 0°, clockwise).
sun_status
enum
normal, midnight_sun (the sun never sets) or polar_night (it never rises). Both polar cases null out sunrise, sunset and day_length, so this tells you which one you got.

Twilight

dawn
time
Civil dawn. Sun 6° below the horizon.
dusk
time
Civil dusk. Sun 6° below the horizon.
nautical_twilight_begin
time
Sun 12° below the horizon, morning.
nautical_twilight_end
time
Sun 12° below the horizon, evening.
first_light
time
Astronomical dawn. The faintest brightening of the sky.
last_light
time
Astronomical dusk. The last trace of sky light.
golden_hour_morning
{ begin, end }
Sun between 4° below and 6° above the horizon, rising.
golden_hour_evening
{ begin, end }
Sun between 6° above and 4° below the horizon, setting.
blue_hour_morning
{ begin, end }
Sun between 6° and 4° below the horizon, rising. Ends where golden_hour_morning begins.
blue_hour_evening
{ begin, end }
Sun between 4° and 6° below the horizon, setting. Begins where golden_hour_evening ends.
golden_hour
time
Start of evening golden hour. Same value as golden_hour_evening.begin, kept for backwards compatibility.

Moon

moonrise
time | null
Moonrise time. Null if the moon doesn't rise that day.
moonset
time | null
Moonset time. Null if the moon doesn't set that day.
moon_phase
string
Named phase: New Moon, Waxing Crescent, First Quarter, Waxing Gibbous, Full Moon, Waning Gibbous, Last Quarter, Waning Crescent.
moon_phase_value
0–1
Continuous phase value. 0 and 1 are new, 0.5 is full.
moon_illumination
percent
Percent of the moon's disk illuminated, 0–100.
moon_always_up
boolean
True at polar latitudes when the moon is circumpolar that day.
moon_always_down
boolean
True when the moon doesn't appear above the horizon.

Location

date
string
Queried date, YYYY-MM-DD.
timezone
string
IANA timezone of the response times.
utc_offset
number
UTC offset in minutes.
elevation
meters
Terrain elevation used in the calculation.

Status codes

Returned in status. The HTTP status matches: 200 for OK and INVALID_TZID, 400 for bad input, 500 for server errors.

OK
Request succeeded.
INVALID_TZID
Timezone didn't validate. Fell back to the location's own zone and returned data anyway.
INVALID_REQUEST
Missing or malformed lat/lng.
INVALID_DATE
Unparseable date, or a range longer than one year.
UNKNOWN_ERROR
Something broke on our end. Retry.

Attribution

Free for personal and commercial use. In return, put a visible link back to sunrisesunset.io on your site.

Powered by <a href="https://sunrisesunset.io">SunriseSunset.io</a>

For AI assistants

A plain-text reference to paste into ChatGPT, Claude or Cursor before asking for code. It lists every parameter and field, plus the edge cases that trip up first drafts: nulls at the poles, utc_offset in minutes, times as strings rather than dates.

There is also an OpenAPI 3.0 spec, as JSON or YAML, for Postman, Insomnia, or generating a typed client.

API reference, plain text
# SunriseSunset.io API reference

Free JSON API for sun and moon times anywhere on Earth. No API key or signup. GET only, CORS enabled, so it can be called directly from a browser.

Endpoint: GET https://api.sunrisesunset.io/json

## Query parameters
- lat (number, REQUIRED): Latitude in decimal degrees.
- lng (number, REQUIRED): Longitude in decimal degrees.
- date (string): Date to query. ISO YYYY-MM-DD, or a relative word like "today" or "tomorrow". Defaults to today in the location's timezone.
- date_start (string): Start of a date range (inclusive). Must be paired with date_end. Up to 365 days.
- date_end (string): End of a date range (inclusive). Returns an array of daily results instead of a single object.
- timezone (IANA tz, default: auto): Return times in this timezone. Defaults to the location's IANA timezone resolved from lat/lng. An invalid value still returns data, with status INVALID_TZID and the detected zone.
- time_format (enum, default: 12): Format of all time fields. One of 12, 24, military, unix. Unix timestamps are always UTC.
- formatted (0 | 1, default: 1): Set to 0 to receive times in ISO 8601 format and day_length in seconds.
- elevation (number | false, default: auto): Elevation override in meters. By default, auto-detected from terrain via ETOPO1. Pass false to compute at sea level. Higher elevation pushes sunrise earlier and sunset later.
- callback (string): JSONP callback function name. Returns application/javascript wrapped in your callback when present.

## Response shape

{ results, status, tzid }. `results` is a single object, or an array of those objects when date_start/date_end is used. On an error, `results` is null and an `error` string replaces `tzid`.

## Fields inside `results`

### Sun
- sunrise (time): Sunrise time.
- sunset (time): Sunset time.
- solar_noon (time): Sun at its highest point.
- day_length (H:MM:SS | seconds): Length of daylight (seconds if formatted=0).
- sunrise_azimuth (degrees): Compass bearing where the sun rises.
- sunset_azimuth (degrees): Compass bearing where the sun sets.
- sun_altitude (degrees): Sun altitude at solar noon.
- sun_azimuth (degrees): Sun azimuth at solar noon (N = 0°, clockwise).
- sun_status (enum): normal, midnight_sun (the sun never sets) or polar_night (it never rises). Both polar cases null out sunrise, sunset and day_length, so this tells you which one you got.

### Twilight
- dawn (time): Civil dawn. Sun 6° below the horizon.
- dusk (time): Civil dusk. Sun 6° below the horizon.
- nautical_twilight_begin (time): Sun 12° below the horizon, morning.
- nautical_twilight_end (time): Sun 12° below the horizon, evening.
- first_light (time): Astronomical dawn. The faintest brightening of the sky.
- last_light (time): Astronomical dusk. The last trace of sky light.
- golden_hour_morning ({ begin, end }): Sun between 4° below and 6° above the horizon, rising.
- golden_hour_evening ({ begin, end }): Sun between 6° above and 4° below the horizon, setting.
- blue_hour_morning ({ begin, end }): Sun between 6° and 4° below the horizon, rising. Ends where golden_hour_morning begins.
- blue_hour_evening ({ begin, end }): Sun between 4° and 6° below the horizon, setting. Begins where golden_hour_evening ends.
- golden_hour (time): Start of evening golden hour. Same value as golden_hour_evening.begin, kept for backwards compatibility.

### Moon
- moonrise (time | null): Moonrise time. Null if the moon doesn't rise that day.
- moonset (time | null): Moonset time. Null if the moon doesn't set that day.
- moon_phase (string): Named phase: New Moon, Waxing Crescent, First Quarter, Waxing Gibbous, Full Moon, Waning Gibbous, Last Quarter, Waning Crescent.
- moon_phase_value (0–1): Continuous phase value. 0 and 1 are new, 0.5 is full.
- moon_illumination (percent): Percent of the moon's disk illuminated, 0–100.
- moon_always_up (boolean): True at polar latitudes when the moon is circumpolar that day.
- moon_always_down (boolean): True when the moon doesn't appear above the horizon.

### Location
- date (string): Queried date, YYYY-MM-DD.
- timezone (string): IANA timezone of the response times.
- utc_offset (number): UTC offset in minutes.
- elevation (meters): Terrain elevation used in the calculation.

## Things that trip people up
- Every time field is a string in the format chosen by time_format/formatted, NOT a Date. Use formatted=0 for ISO 8601 if you plan to parse it.
- Any time field can be null when the event does not happen that day. Read sun_status before assuming a null sunrise is a bug: midnight_sun and polar_night are normal at high latitudes.
- day_length is an H:MM:SS string by default and a number of seconds when formatted=0.
- utc_offset is in MINUTES, not hours (-240 means UTC-4).
- golden_hour is a single time kept for backwards compatibility, equal to golden_hour_evening.begin. Prefer the {begin, end} window fields for new code.
- A sunset after local midnight carries the next calendar date, so in ISO mode sunset can look 'before' sunrise as text. Compare timestamps, not strings.
- status can be OK, INVALID_TZID, INVALID_REQUEST, INVALID_DATE or UNKNOWN_ERROR. INVALID_TZID still returns full data with a fallback timezone and HTTP 200.
- Times for a past date never change. Cache them rather than re-requesting.

## Machine-readable spec
An OpenAPI 3.0 description is served at https://sunrisesunset.io/openapi.json, and as YAML at https://sunrisesunset.io/api/openapi.yaml. Import it into Postman or Insomnia, generate a typed client from it, or fetch it directly.

## Attribution (required)
The API is free for commercial use in exchange for a visible backlink: Powered by <a href="https://sunrisesunset.io">SunriseSunset.io</a>

## Example

curl 'https://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873&date=2026-06-21'

{
  "results": {
    "date": "2026-06-21",
    "sunrise": "5:41:58 AM",
    "sunset": "8:38:05 PM",
    "first_light": "3:42:23 AM",
    "last_light": "10:37:39 PM",
    "dawn": "5:09:48 AM",
    "dusk": "9:10:15 PM",
    "solar_noon": "1:10:02 PM",
    "golden_hour": "7:58:03 PM",
    "day_length": "14:56:06",
    "nautical_twilight_begin": "4:29:11 AM",
    "nautical_twilight_end": "9:50:51 PM",
    "timezone": "America/New_York",
    "utc_offset": -240,
    "sun_altitude": 74.54,
    "sun_azimuth": 180,
    "sunrise_azimuth": 58.3,
    "sunset_azimuth": 301.7,
    "moonrise": "1:01:52 PM",
    "moonset": "12:41:20 AM",
    "moon_illumination": 47.57,
    "moon_phase": "First Quarter",
    "moon_phase_value": 0.24,
    "moon_always_up": false,
    "moon_always_down": false,
    "elevation": 26,
    "sun_status": "normal",
    "golden_hour_morning": {
      "begin": "5:22:29 AM",
      "end": "6:22:00 AM"
    },
    "golden_hour_evening": {
      "begin": "7:58:03 PM",
      "end": "8:57:33 PM"
    },
    "blue_hour_morning": {
      "begin": "5:09:48 AM",
      "end": "5:22:29 AM"
    },
    "blue_hour_evening": {
      "begin": "8:57:33 PM",
      "end": "9:10:15 PM"
    }
  },
  "status": "OK",
  "tzid": "America/New_York"
}

FAQ

Do I need an API key?
No. The keyless endpoint covers most apps. For higher limits or per-app usage tracking, sign in and mint a key, then send it as Authorization: Bearer sss_.... Keep it out of the query string, since proxies and CDNs log URLs.
How accurate are the times?
To the second, astronomically. Atmospheric refraction and terrain elevation are both factored in by default.
What if the sun or moon never rises or sets that day?
Those fields come back null. sun_status says whether it was midnight_sun or polar_night, and for the moon moon_always_up or moon_always_down flips to true.
What's the difference between golden hour and blue hour?
Golden hour is the warm light with the sun between 4° below and 6° above the horizon. Blue hour is the deeper light just outside it, sun between 6° and 4° below. Both come back as { begin, end } windows for morning and evening, and they meet exactly: blue_hour_morning.end equals golden_hour_morning.begin. Near the poles either half can be null.
Are there rate limits?
None enforced, within reason. If you'd be calling it hourly per user, cache on your end. Times for a past date never change.

Changelog

Status page
Golden hour and blue hour as begin/end windows, morning and evening. New sun_status field separates midnight sun from polar night. Additive only; every existing field is unchanged, including golden_hour.
Moon data (rise/set, phase, illumination), sun altitude/azimuth at solar noon + rise + set, automatic elevation from terrain.
JSONP callback, formatted=0 for ISO 8601 output, nautical twilight fields, granular status codes.
Fixed a DST edge-case that could return the wrong day at the boundary.
time_format option (12, 24, military, unix).
date_start + date_end range queries, up to 365 days.
Lower response times; migrated onto Cloudflare Workers.
utc_offset added to responses.
first_light + last_light fields (astronomical twilight).
API released.