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.
https://api.sunrisesunset.io/json?lat=38.9&lng=-77fetch("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
{
"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.
https://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873Send a request to see the response here.Examples
- Todayhttps://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873
- Specific datehttps://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873&date=2026-06-21&timezone=UTC
- One-year rangehttps://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873&date_start=2026-01-01&date_end=2026-12-31
- 24-hour timeshttps://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873&time_format=24
- Unix timestampshttps://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873&time_format=unix
- ISO 8601https://api.sunrisesunset.io/json?lat=38.907192&lng=-77.036873&formatted=0
Parameters
Query-string values on a single GET request.
latnumberrequiredLatitude in decimal degrees.
Example
38.907192lngnumberrequiredLongitude in decimal degrees.
Example
-77.036873datestringDate 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-21date_startstringStart of a date range (inclusive). Must be paired with date_end. Up to 365 days.
date_endstringEnd of a date range (inclusive). Returns an array of daily results instead of a single object.
timezoneIANA tzReturn 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
autoExampleAmerica/New_Yorktime_formatenumFormat of all time fields. One of 12, 24, military, unix. Unix timestamps are always UTC.
Default
12formatted0 | 1Set to 0 to receive times in ISO 8601 format and day_length in seconds.
Default
1elevationnumber | falseElevation 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
autocallbackstringJSONP 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_statussays whether it wasmidnight_sunorpolar_night, and for the moonmoon_always_upormoon_always_downflips 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.endequalsgolden_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.