# Public Holidays Scraper — Any Country, Any Year, Next Holidays (`yadroo/public-holidays`) Actor

Public holidays for 204 countries: full year or multi-year calendars, upcoming holidays, is-today-a-holiday checks, long weekends with bridge days, school holidays (36 countries), regional filters. Local + English names, weekday, days-from-now. No API key.

- **URL**: https://apify.com/yadroo/public-holidays.md
- **Developed by:** [Samat Makatov](https://apify.com/yadroo) (community)
- **Categories:** Travel, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.35 / 1,000 result items

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Public holiday calendars for **204 countries** as clean JSON: a full year or several years, the holidays coming up in the next N days, "is this date a holiday?" checks, long weekends with bridge days, regional (state-level) filtering, and school holidays for 36 countries. Local and English names, weekday, days-from-now and stable ids on every row. Built for scheduling agents, HR, logistics and market research. **No API key, no proxy, no browser** — data comes from the public Nager.Date and OpenHolidays APIs.

### Use cases

- **Delivery & SLA planning** — skip non-working days when computing lead times or SLA deadlines per country (`mode: next`, `skipWeekendHolidays`).
- **Scheduling agents** — before booking a call or sending a campaign, ask `isHoliday` for the counterparty's country and get the next holiday too.
- **HR / payroll** — annual calendars for every office country with state-level rules (`subdivision: "DE-BY"`, `types: ["Public"]`).
- **Travel & hospitality demand** — long weekends and bridge days per country/year (`longWeekends`), school holidays by German/Austrian/Swiss state (`school`).
- **Retail & ads calendars** — multi-year, multi-country holiday lists to align promotions and budgets (`range`, `layout: perCountry`).
- **Support staffing** — one summary row per country with weekday-vs-weekend holiday counts and by-month distribution.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `countries` | string\[] | — (needed in every mode except `nextWorldwide`; Console prefill `KZ`, `US`, `DE`) | ISO 3166-1 alpha-2 codes; English names and aliases (`Germany`, `UK`, `USA`) also work, in any letter case. 204 codes in the Reference below. Optional for `nextWorldwide` (acts as a filter there). An unknown value is skipped and named in the status with a suggestion (`"Germny" (did you mean DE?)`); if none of the values can be read, the run stops with that message instead of returning every country. |
| `mode` | enum | `year` | `year`, `range`, `next`, `isHoliday`, `longWeekends`, `school`, `countryInfo`, `nextWorldwide` — see table below. |
| `year` | integer | current year (no stored default: an empty field always means the year of the run) | For `year`, `longWeekends`, `countryInfo`. Nager.Date supports roughly 1975–2100, varies by country (KZ starts later; an unsupported year is reported in `SUMMARY.errors`). |
| `yearFrom` / `yearTo` | integer | `year`, else current year / `yearFrom` | Year span for `range` (max 10 years per run). |
| `startDate` / `endDate` | `YYYY-MM-DD` | — | Inclusive date window. Post-filter in every calendar mode; in `range`/`school` also decides which years to fetch. |
| `nextDays` | integer 1–730 | 365 | Horizon for `next`. |
| `date` | `YYYY-MM-DD` | today | Day to check in `isHoliday`. |
| `utcOffsetHours` | integer −12…14 | 0 | Which calendar date counts as "today" (5 = Kazakhstan, −5 = New York). Affects `next`, `isHoliday`, `daysFromNow`. |
| `types` | string\[] | all | `Public`, `Bank`, `School`, `Authorities`, `Optional`, `Observance` (Nager); `BackToSchool`, `EndOfLessons` (OpenHolidays school calendar). |
| `nationalOnly` | boolean | false | Drop regional holidays (limited to certain states/counties). |
| `subdivision` | string | — | ISO 3166-2 code (`DE-BY`, `US-CA`, `ES-CT`; prefix optional for single-country runs). Keeps nationwide + that region's holidays; long weekends then count that region's holidays too, and school calendars are read for it. |
| `skipWeekendHolidays` | boolean | false | Keep only holidays that fall Mon–Fri (the ones that cost a working day). |
| `source` | enum | `auto` | `auto` (Nager.Date, OpenHolidays fallback), `nager`, `openholidays`. `school` always uses OpenHolidays. |
| `language` | ISO 639-1 | `EN` (when empty) | Name language for OpenHolidays requests (`DE`, `FR`, `ES`…). |
| `availableBridgeDays` | integer 1–3 | 1 | `longWeekends`: vacation days an employee may spend on each side of a holiday to join it to a weekend. |
| `layout` | enum | `rows` | `rows` = one row per holiday; `perCountry` = one row per country with counts + embedded `holidays[]`. |
| `dedupe` | boolean | true | Drop repeated rows with the same country + states/regions (`subdivisions`) + start/end date + name. Rows for different states are never merged, so school holidays stay one row per state. |
| `fields` | string\[] | all columns | Keep only these columns, in this order; `countryCode` always comes first unless you list it elsewhere. Letter case is forgiven. Unknown names (with a suggestion) and columns of another mode are named in the status; a list with no column of this mode's rows stops the run and lists the valid ones. Columns per row type: Output below. |
| `maxItems` | integer | 5000 | Cost cap. A country-year is ~10–20 rows. |

Original inputs `countries`, `year`, `mode` (`year`/`next`/`longWeekends`) keep their meaning. `mode`, `source`, `layout` and `types` are fixed lists: Apify refuses any other value before the run starts and shows the allowed ones (listed in this README).

#### Modes

| `mode` | Rows | Source | Typical question |
|---|---|---|---|
| `year` | holiday | Nager (OH fallback) | "All 2026 holidays in KZ, US, DE" |
| `range` | holiday | Nager / OH | "Holidays 2026–2028" or "between 2026-11-01 and 2027-01-15" |
| `next` | holiday | Nager / OH | "What is coming in the next 90 days?" |
| `isHoliday` | dayCheck | Nager / OH | "Is 2026-10-25 a day off in Kazakhstan? When is the next one?" |
| `longWeekends` | longWeekend | Nager (computed by the actor with `subdivision` or 2–3 bridge days, see FAQ) | "Long weekends in 2027 if I can take 2 bridge days" |
| `school` | holiday (`School`, `BackToSchool`, `EndOfLessons`) | OpenHolidays (36 countries) | "Bavarian school holidays 2026/27" |
| `countryInfo` | countryInfo | Nager | Names, region, borders, holidays per year |
| `nextWorldwide` | holiday | Nager | "Every public holiday worldwide in the coming days" (Nager's global feed, ~1 week ahead) |

### Reference

#### Countries (204, Nager.Date). † = also in OpenHolidays (school holidays, localized names, half-day flags)

| Code | Country | Code | Country | Code | Country | Code | Country |
|---|---|---|---|---|---|---|---|
| `AD` † | Andorra | `DM` | Dominica | `KY` | Cayman Islands | `RO` † | Romania |
| `AG` | Antigua and Barbuda | `DO` | Dominican Republic | `KZ` | Kazakhstan | `RS` † | Serbia |
| `AI` | Anguilla | `DZ` | Algeria | `LC` | Saint Lucia | `RU` | Russia |
| `AL` † | Albania | `EC` | Ecuador | `LI` † | Liechtenstein | `RW` | Rwanda |
| `AM` | Armenia | `EE` † | Estonia | `LR` | Liberia | `SB` | Solomon Islands |
| `AO` | Angola | `EG` | Egypt | `LS` | Lesotho | `SC` | Seychelles |
| `AR` | Argentina | `ER` | Eritrea | `LT` † | Lithuania | `SD` | Sudan |
| `AT` † | Austria | `ES` † | Spain | `LU` † | Luxembourg | `SE` † | Sweden |
| `AU` | Australia | `ET` | Ethiopia | `LV` † | Latvia | `SG` | Singapore |
| `AW` | Aruba | `FI` | Finland | `LY` | Libya | `SH` | Saint Helena, Ascension and Tristan da Cunha |
| `AX` | Åland Islands | `FK` | Falkland Islands | `MA` | Morocco | `SI` † | Slovenia |
| `BA` | Bosnia and Herzegovina | `FM` | Micronesia | `MC` † | Monaco | `SJ` | Svalbard and Jan Mayen |
| `BB` | Barbados | `FO` | Faroe Islands | `MD` † | Moldova | `SK` † | Slovakia |
| `BD` | Bangladesh | `FR` † | France | `ME` | Montenegro | `SL` | Sierra Leone |
| `BE` † | Belgium | `GA` | Gabon | `MF` | Saint Martin | `SM` † | San Marino |
| `BF` | Burkina Faso | `GB` | United Kingdom | `MG` | Madagascar | `SN` | Senegal |
| `BG` † | Bulgaria | `GD` | Grenada | `MH` | Marshall Islands | `SO` | Somalia |
| `BH` | Bahrain | `GE` | Georgia | `MK` | North Macedonia | `SR` | Suriname |
| `BI` | Burundi | `GF` | French Guiana | `ML` | Mali | `SS` | South Sudan |
| `BJ` | Benin | `GG` | Guernsey | `MN` | Mongolia | `ST` | São Tomé and Príncipe |
| `BL` | Saint Barthélemy | `GH` | Ghana | `MP` | Northern Mariana Islands | `SV` | El Salvador |
| `BM` | Bermuda | `GI` | Gibraltar | `MQ` | Martinique | `SX` | Sint Maarten |
| `BO` | Bolivia | `GL` | Greenland | `MR` | Mauritania | `SY` | Syria |
| `BQ` | Caribbean Netherlands | `GM` | Gambia | `MS` | Montserrat | `SZ` | Eswatini |
| `BR` † | Brazil | `GN` | Guinea | `MT` † | Malta | `TC` | Turks and Caicos Islands |
| `BS` | Bahamas | `GP` | Guadeloupe | `MW` | Malawi | `TD` | Chad |
| `BW` | Botswana | `GQ` | Equatorial Guinea | `MX` † | Mexico | `TG` | Togo |
| `BY` † | Belarus | `GR` | Greece | `MZ` | Mozambique | `TK` | Tokelau |
| `BZ` | Belize | `GT` | Guatemala | `NA` | Namibia | `TN` | Tunisia |
| `CA` | Canada | `GW` | Guinea-Bissau | `NC` | New Caledonia | `TO` | Tonga |
| `CC` | Cocos (Keeling) Islands | `GY` | Guyana | `NE` | Niger | `TR` | Türkiye |
| `CD` | DR Congo | `HK` | Hong Kong | `NF` | Norfolk Island | `TT` | Trinidad and Tobago |
| `CF` | Central African Republic | `HN` | Honduras | `NG` | Nigeria | `TV` | Tuvalu |
| `CG` | Congo | `HR` † | Croatia | `NI` | Nicaragua | `TZ` | Tanzania |
| `CH` † | Switzerland | `HT` | Haiti | `NL` † | Netherlands | `UA` | Ukraine |
| `CI` | Ivory Coast | `HU` † | Hungary | `NO` | Norway | `UG` | Uganda |
| `CK` | Cook Islands | `ID` | Indonesia | `NR` | Nauru | `US` | United States |
| `CL` | Chile | `IE` † | Ireland | `NU` | Niue | `UY` | Uruguay |
| `CM` | Cameroon | `IM` | Isle of Man | `NZ` | New Zealand | `VA` † | Vatican City |
| `CN` | China | `IQ` | Iraq | `PA` | Panama | `VC` | Saint Vincent and the Grenadines |
| `CO` | Colombia | `IS` | Iceland | `PE` | Peru | `VE` | Venezuela |
| `CR` | Costa Rica | `IT` † | Italy | `PF` | French Polynesia | `VG` | British Virgin Islands |
| `CU` | Cuba | `JE` | Jersey | `PG` | Papua New Guinea | `VI` | United States Virgin Islands |
| `CV` | Cape Verde | `JM` | Jamaica | `PH` | Philippines | `VN` | Vietnam |
| `CW` | Curaçao | `JP` | Japan | `PL` † | Poland | `VU` | Vanuatu |
| `CX` | Christmas Island | `KE` | Kenya | `PM` | Saint Pierre and Miquelon | `WF` | Wallis and Futuna |
| `CY` | Cyprus | `KH` | Cambodia | `PN` | Pitcairn Islands | `WS` | Samoa |
| `CZ` † | Czechia | `KI` | Kiribati | `PR` | Puerto Rico | `YE` | Yemen |
| `DE` † | Germany | `KM` | Comoros | `PT` † | Portugal | `ZA` † | South Africa |
| `DJ` | Djibouti | `KN` | Saint Kitts and Nevis | `PW` | Palau | `ZM` | Zambia |
| `DK` | Denmark | `KR` | South Korea | `PY` | Paraguay | `ZW` | Zimbabwe |

Live lists: [Nager.Date AvailableCountries](https://date.nager.at/api/v3/AvailableCountries), [OpenHolidays Countries](https://openholidaysapi.org/Countries) and [Subdivisions](https://openholidaysapi.org/Subdivisions?countryIsoCode=DE) (state codes for `subdivision`).

#### Holiday types

| Type | Meaning | Source |
|---|---|---|
| `Public` | Official public holiday, day off | both |
| `Bank` | Banks and offices closed | both |
| `School` | Schools closed (Nager) / school vacation period (OpenHolidays, has `endDate`) | both |
| `Authorities` | Government offices closed | Nager |
| `Optional` | Most people take the day off | both |
| `Observance` | Observed, not a day off | Nager |
| `BackToSchool` / `EndOfLessons` | First / last school day | OpenHolidays (`school`) |

Most countries only carry `Public`; US, CA, GB, AU, DE, AT, CH and a few others also list Bank/School/Observance/Optional entries.

#### Subdivision codes (examples)

`DE-BW DE-BY DE-BE DE-BB DE-HB DE-HH DE-HE DE-MV DE-NI DE-NW DE-RP DE-SL DE-SN DE-ST DE-SH DE-TH` · `US-CA US-NY US-TX …` · `AT-1…AT-9` · `CH-ZH CH-BE …` · `ES-CT ES-MD …` · `KZ-75` (Almaty). Nager returns them in `subdivisions`; OpenHolidays lists them per country at `/Subdivisions`.

### Examples

**Annual calendar for all office countries, official days off only**

```json
{ "countries": ["KZ", "DE", "PL", "US"], "year": 2026, "types": ["Public"], "nationalOnly": true }
```

**Upcoming non-working days for delivery planning (Kazakhstan time)**

```json
{ "countries": ["KZ", "RU", "UZ", "CN"], "mode": "next", "nextDays": 60, "skipWeekendHolidays": true, "utcOffsetHours": 5 }
```

**Is it a holiday there? (scheduling agent)**

```json
{ "countries": ["DE", "GB", "US"], "mode": "isHoliday", "date": "2026-10-03", "subdivision": "DE-BY" }
```

**Long weekends 2027 with up to 2 bridge days (travel offers)**

```json
{ "countries": ["DE", "AT", "CH", "NL"], "mode": "longWeekends", "year": 2027, "availableBridgeDays": 2 }
```

**Bavarian school holidays for the 2026/27 school year, German names**

```json
{ "countries": ["DE"], "mode": "school", "subdivision": "DE-BY", "startDate": "2026-09-01", "endDate": "2027-08-31", "language": "DE" }
```

**Three-year multi-country planning table, one row per country**

```json
{ "countries": ["FR", "IT", "ES", "PT"], "mode": "range", "yearFrom": 2026, "yearTo": 2028, "types": ["Public"], "layout": "perCountry" }
```

### Output

Holiday row (modes `year`, `range`, `next`, `school`, `nextWorldwide`):

```json
{
  "id": "DE:2026-01-06:epiphany",
  "type": "holiday",
  "countryCode": "DE",
  "country": "Germany",
  "date": "2026-01-06",
  "endDate": "2026-01-06",
  "name": "Epiphany",
  "localName": "Heilige Drei Könige",
  "year": 2026,
  "month": 1,
  "weekday": "Tuesday",
  "isWeekend": false,
  "daysFromNow": -250,
  "holidayTypes": ["Public"],
  "national": false,
  "subdivisions": ["DE-BW", "DE-BY", "DE-ST"],
  "regionalScope": "Regional",
  "temporalScope": null,
  "fixed": false,
  "launchYear": null,
  "source": "nager",
  "sourceUrl": "https://date.nager.at/api/v3/PublicHolidays/2026/DE",
  "fetchedAt": "2026-09-13T08:02:48.049Z"
}
```

| Field | Description |
|---|---|
| `id` | Stable `CC:date:slug(name)` — safe for diffing across runs; regional rows (school holidays, state holidays from OpenHolidays) can share an `id` across states, so key them by `id` + `subdivisions` |
| `type` | `holiday`, `dayCheck`, `longWeekend`, `countrySummary` or `countryInfo` |
| `date` / `endDate` | Same day for holidays; school vacations span several days |
| `name` / `localName` | English (or `language`) name / name in the country's language |
| `weekday`, `isWeekend`, `daysFromNow` | Computed vs. "today" in `utcOffsetHours` (negative = past) |
| `holidayTypes` | See Holiday types |
| `national` / `subdivisions` | Nationwide flag; ISO 3166-2 codes when regional |
| `regionalScope` / `temporalScope` | `National`/`Regional`/`Local`; `FullDay`/`HalfDay` (OpenHolidays only) |
| `fixed`, `launchYear` | Fixed calendar date; year the holiday was introduced (Nager only) |
| `source`, `sourceUrl`, `fetchedAt` | Provenance |

Other row types:

- `dayCheck` (`isHoliday`): `date`, `weekday`, `isWeekend`, `isPublicHoliday`, `isHoliday`, `isWorkingDay`, `holidays[]` (name, localName, types, national, subdivisions), `nextHoliday {date, name, localName, weekday, daysUntil, national}`.
- `longWeekend`: `startDate`, `endDate`, `startWeekday`, `endWeekday`, `dayCount`, `needBridgeDay`, `bridgeDays[]`, `daysFromNow`.
- `countrySummary` (`layout: perCountry`): `years`, `total`, `publicHolidays`, `national`, `regional`, `onWeekdays`, `onWeekends`, `byMonth`, `byType`, `nextHoliday`, `holidays[]`.
- `countryInfo`: `officialName`, `nativeName`, `region`, `borders[]`, `borderNames[]`, `publicHolidaysInYear` (null when that year's calendar could not be read), `openHolidaysCoverage`.
- Countries that fail (unsupported year, source cannot serve the country, API error) are not rows and are not charged: they are listed in `SUMMARY.errors` (`{ country, error }`, plus `errorCount`) and in the run's status message. The run continues with the other countries and fails only when nothing at all could be fetched.

Columns per row type, in output order (for `fields`):

| Row type | Columns |
|---|---|
| `holiday` | `id`, `type`, `countryCode`, `country`, `date`, `endDate`, `name`, `localName`, `year`, `month`, `weekday`, `isWeekend`, `daysFromNow`, `holidayTypes`, `national`, `subdivisions`, `regionalScope`, `temporalScope`, `fixed`, `launchYear`, `source`, `sourceUrl`, `fetchedAt` |
| `dayCheck` | `type`, `countryCode`, `country`, `date`, `weekday`, `isWeekend`, `isPublicHoliday`, `isHoliday`, `isWorkingDay`, `holidays`, `nextHoliday`, `source`, `fetchedAt` |
| `longWeekend` | `id`, `type`, `countryCode`, `country`, `year`, `startDate`, `endDate`, `startWeekday`, `endWeekday`, `dayCount`, `needBridgeDay`, `bridgeDays`, `daysFromNow`, `source`, `sourceUrl`, `fetchedAt` |
| `countrySummary` | `type`, `countryCode`, `country`, `years`, `from`, `to`, `total`, `publicHolidays`, `national`, `regional`, `onWeekdays`, `onWeekends`, `byMonth`, `byType`, `nextHoliday`, `holidays`, `source`, `fetchedAt` |
| `countryInfo` | `type`, `countryCode`, `country`, `officialName`, `nativeName`, `region`, `borders`, `borderNames`, `year`, `publicHolidaysInYear`, `openHolidaysCoverage`, `source`, `sourceUrl`, `fetchedAt` |

The dataset has a view per row type (Holidays, Is it a holiday?, Long weekends, Per country, Country info).

The run's status message says how many rows were saved and names failed, unknown and unfetched countries. The key-value store record `SUMMARY` holds mode, countries, unknown inputs with suggestions, how free-text countries were read, years, window, sources used, `fields`, item count (`items`, `delivered`), per-country `errors` and `errorCount`, `countriesNotFetched`, and `stoppedBy` (`limit`, `timeout` or null).

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~public-holidays/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"countries":["KZ","DE"],"mode":"next","nextDays":90,"skipWeekendHolidays":true}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/public-holidays').call({ countries: ['US'], mode: 'isHoliday', date: '2026-11-26', utcOffsetHours: -5 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].isWorkingDay, items[0].nextHoliday);
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/public-holidays").call(run_input={"countries": ["DE", "AT", "CH"], "mode": "longWeekends", "year": 2027, "availableBridgeDays": 2})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

MCP: connect `https://mcp.apify.com` and call the `yadroo/public-holidays` tool with the same JSON — the input schema is self-describing, so an agent can pick `mode` and filters on its own.

### Pricing

Pay per event: **$0.001 per run start + $0.0005 per dataset row**. Store discounts: Bronze −10 %, Silver −20 %, Gold and above −30 % on the row price; the start event is the same on every plan; platform usage is included. Typical runs: 3 countries × 1 year ≈ 45 rows ≈ $0.02; an `isHoliday` check for 10 countries = 10 rows ≈ $0.006; 4 countries × 3 years ≈ 180 rows ≈ $0.09 (or 4 rows with `layout: perCountry`). Failed countries produce no rows and cost nothing beyond the start.

Your **maximum cost per run** is respected: the run stores only the rows it pays for, then ends with the status "Stopped at your spending limit: N rows delivered". `maxItems` caps the rows as well.

### Limits & FAQ

- **Coverage.** Nager.Date: 204 countries, English + local names, years roughly 1975–2100 (per-country; e.g. KZ starts in the 1990s — unsupported years are listed in `SUMMARY.errors` with the API message). OpenHolidays: 36 countries (see †), 2020–2030, names in every official language, half-day flags, school calendars.
- **Substitute days.** Sources list the official holiday date; "Monday in lieu" days are included only where the source provides them (GB, AU, US mostly; KZ/RU government-decreed transfers are often missing). For payroll-grade accuracy verify against the local gazette.
- **Rate limits and run length.** Both APIs are free, CDN-cached and unauthenticated; the actor spaces requests ~120 ms apart and retries 429/5xx with backoff. One country-year takes about 0.2–0.4 s with its rows saved (measured 03.10.2026), so a few hundred country-years finish in one to two minutes and the widest run (204 countries × 10 years, with `maxItems` raised) in about 12 minutes, inside the default 15-minute timeout. A run that nears its timeout stops starting new countries, keeps every row already saved and ends with "Stopped before the run timeout: N rows saved".
- **Long weekends with a state or more bridge days.** Nager.Date's long-weekend endpoint answers only the default question (1 bridge day, nationwide holidays): on 03.10.2026 it returned the same list for 1, 2 and 3 bridge days and for `DE` vs `DE-BY`. So with `subdivision` or 2–3 bridge days the actor computes long weekends itself from the Nager.Date calendar, with Nager's rules and each country's weekend days (Friday–Saturday in Egypt or Bahrain, Sunday only in Mexico or the Philippines). For the default question the two give identical results on 16 countries × 2 years. Those rows carry the calendar's URL in `sourceUrl`.
- **Freshness.** Nager.Date responses are cached up to 7 days on their CDN; holidays announced at short notice may lag.
- **`name` vs `localName` with OpenHolidays.** The API returns only the requested `language`; ask for `EN` (default) to get English names, or set `language` to the local code and both fields carry the local name.
- **Errors.** Unknown country strings are skipped and named in the status with a suggestion; when none can be read the run stops with that message. Countries a source cannot serve are listed in `SUMMARY.errors` (no row, not charged); the run fails only when no country produced data.
- **Restarts.** If Apify migrates or restarts the run, rows already saved are not saved or charged again.
- **Roadmap.** Working-day counters between two dates, ICS export, holiday diffs between runs.

***

Made by **Yadroo** · Sibling actors: [open-meteo-weather](https://apify.com/yadroo/open-meteo-weather) · [osm-geocode](https://apify.com/yadroo/osm-geocode) · [world-bank-indicators](https://apify.com/yadroo/world-bank-indicators) · [fx-rates](https://apify.com/yadroo/fx-rates) · [ip-intel](https://apify.com/yadroo/ip-intel)

# Actor input Schema

## `countries` (type: `array`):

ISO 3166-1 alpha-2 codes (`KZ`, `US`, `DE`, `GB`…). English names and common aliases (`Germany`, `UK`, `USA`) are also accepted; letter case, accents and a space instead of a hyphen do not matter. 204 countries supported (full list in the README). Needed in every mode except `nextWorldwide` (there it acts as a filter). An unknown value is skipped and named in the status with a suggestion; if no value can be read, the run stops with that message.

## `mode` (type: `string`):

What to fetch. `year` / `next` / `longWeekends` are the original modes; the others were added for scheduling, HR, logistics and market-research jobs. One dataset row per holiday (or per country in layout `perCountry`).

## `year` (type: `integer`):

Calendar year for modes `year`, `longWeekends`, `countryInfo` (and the first year of `range` when `yearFrom` is empty). Empty = the current year on the day of the run (in `utcOffsetHours`). Nager.Date typically covers 1975–2100 (varies by country; an out-of-range year is reported for that country in the SUMMARY record, not as a row).

## `yearFrom` (type: `integer`):

First year for mode `range` (max 10 years per run). Empty = `year`, or the current year. Ignored when startDate/endDate are set.

## `yearTo` (type: `integer`):

Last year (inclusive) for mode `range`. Defaults to `yearFrom`.

## `startDate` (type: `string`):

Inclusive lower bound `YYYY-MM-DD`. Works in every calendar mode (`year`, `range`, `school`, `longWeekends`) as a post-filter; with `range`/`school` it also defines which years are fetched.

## `endDate` (type: `string`):

Inclusive upper bound `YYYY-MM-DD`.

## `nextDays` (type: `integer`):

Mode `next`: how far ahead to look from today.

## `date` (type: `string`):

Mode `isHoliday`: the day to check (`YYYY-MM-DD`). Default: today in `utcOffsetHours`.

## `utcOffsetHours` (type: `integer`):

Defines the calendar date of "today" used by `next`, `isHoliday` and `daysFromNow` (e.g. 5 for Kazakhstan, -5 for New York). Default UTC.

## `types` (type: `array`):

Keep only holidays of these types. Empty = all. Most countries only have `Public`; US/CA/GB/AU/DE… also carry Bank/School/Observance/Optional. School-calendar types come from mode `school`.

## `nationalOnly` (type: `boolean`):

Drop regional holidays (those limited to certain states/counties, e.g. Epiphany in DE-BW/BY/ST).

## `subdivision` (type: `string`):

ISO 3166-2 code such as `DE-BY`, `US-CA`, `ES-CT` (prefix optional when a single country is requested). Keeps nationwide holidays plus the ones valid in this subdivision; long weekends then count that subdivision's holidays too, and OpenHolidays school calendars are read for it. Applies only to the matching country in multi-country runs.

## `skipWeekendHolidays` (type: `boolean`):

Keep only holidays that actually remove a working day (Mon–Fri). Note: substitute days-off (e.g. "Monday after") are only included where the source lists them.

## `source` (type: `string`):

Nager.Date covers 204 countries with English + local names. OpenHolidays covers 36 (mostly European) countries with names in every official language, `regionalScope`/`temporalScope` and school holidays; it is always used for mode `school`.

## `language` (type: `string`):

ISO 639-1 code for OpenHolidays requests (`EN`, `DE`, `FR`, `ES`…). Empty = `EN`. `localName` uses the country's first official language; `name` stays English when available.

## `availableBridgeDays` (type: `integer`):

Mode `longWeekends`: how many vacation days an employee can spend on each side of a holiday to join it to a weekend. 1 = Nager.Date's own long weekends; with 2–3 (or a `subdivision`) the actor computes them from the calendar with the same rules.

## `layout` (type: `string`):

`perCountry` is handy for agents and dashboards: total / national / regional / weekday counts, by-month and by-type breakdowns, next holiday, plus the `holidays` array. Applies to `year`, `range`, `next`, `school`.

## `dedupe` (type: `boolean`):

Drop repeated rows with the same country, states/regions (subdivisions), start and end date and name. Rows for different states are kept apart, so school holidays stay one row per state.

## `fields` (type: `array`):

Keep only these columns, in this order, e.g. `["date", "name", "localName"]`. `countryCode` always comes first unless you list it elsewhere. Empty = every column of the mode. Letter case is forgiven; an unknown name (with a suggestion) or a column of another mode is named in the status; a list with no column of this mode's rows stops the run with the valid names. Column lists per row type: README → Output.

## `maxItems` (type: `integer`):

Stop after this many dataset rows (cost cap). A country-year is ~10–20 rows.

## Actor input object example

```json
{
  "countries": [
    "KZ",
    "US",
    "DE"
  ],
  "mode": "year",
  "nextDays": 365,
  "utcOffsetHours": 0,
  "nationalOnly": false,
  "skipWeekendHolidays": false,
  "source": "auto",
  "availableBridgeDays": 1,
  "layout": "rows",
  "dedupe": true,
  "maxItems": 5000
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "countries": [
        "KZ",
        "US",
        "DE"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/public-holidays").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "countries": [
        "KZ",
        "US",
        "DE",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("yadroo/public-holidays").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "countries": [
    "KZ",
    "US",
    "DE"
  ]
}' |
apify call yadroo/public-holidays --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yadroo/public-holidays"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rDMayzPSW1gGc3o2n/builds/n7dnnvNu34VVLTb4s/openapi.json
