# iCalendar (.ics) Validator (`landlordtools/ics-calendar-validator`) Actor

Validate .ics calendar files and feeds against RFC 5545: line endings and folding, required properties, nesting, dates, DTEND vs DTSTART, duplicate UIDs and TEXT escaping, with line numbers. See README.

- **URL**: https://apify.com/landlordtools/ics-calendar-validator.md
- **Developed by:** [LandlordTools](https://apify.com/landlordtools) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 calendar results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## iCalendar (.ics) Validator

Validate calendar files and feeds against the iCalendar standard, RFC 5545 [1], before you publish them or send them to customers. Paste one file, or give up to 50 public URLs (http, https or webcal). You get one dataset row per calendar: whether it is valid, and every error and warning with its line number.

Calendar apps are forgiving in different ways, so a feed that works in one app can fail silently in another. This Actor flags the problems that usually cause that.

### What it checks

**Errors** (the standard says MUST):

- line breaks that aren't CRLF
- unbalanced or mismatched BEGIN/END, or a first component that isn't VCALENDAR
- missing VERSION:2.0 or PRODID
- events or to-dos without UID or DTSTAMP, and events without DTSTART (unless the calendar has a METHOD)
- invalid or impossible dates and times, TZID together with a UTC "Z" time, and dates mixed with date-times
- DTEND or DUE before DTSTART, DTEND together with DURATION, and badly formed durations
- alarms without ACTION or TRIGGER, and DISPLAY or EMAIL alarms without a DESCRIPTION
- properties that appear more than once where only one is allowed

**Warnings** (the standard says SHOULD, or it's a likely mistake):

- lines over 75 octets that aren't folded
- unescaped `;` or `,` and undefined escapes in TEXT values
- duplicate UIDs
- an all-day event whose DTEND is the same day (DTEND is exclusive)
- events without a SUMMARY
- a byte-order mark, blank lines, and feeds not served as `text/calendar`

### Input

```json
{
  "icsText": "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Example//EN\r\nBEGIN:VEVENT\r\nUID:1@example.com\r\nDTSTAMP:20261003T000000Z\r\nDTSTART;VALUE=DATE:20261215\r\nDTEND;VALUE=DATE:20261215\r\nSUMMARY:Registration opens; West Midlands\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"
}
```

- `icsText`: optional, the contents of one .ics file, up to 5 MB.
- `urls`: optional, up to 50 calendar URLs. Each is fetched once, up to 5 MB. Only http, https and webcal URLs are fetched (webcal is fetched over https).

### Example output

```json
{
  "source": "icsText",
  "valid": true,
  "errorCount": 0,
  "warningCount": 2,
  "warnings": [
    {
      "line": 8,
      "message": "All-day event ends on the day it starts; DTEND is exclusive, so it should be the next day."
    },
    {
      "line": 9,
      "message": "SUMMARY has an unescaped \";\" or \",\"; in TEXT values these should be written as \"\\;\" and \"\\,\"."
    }
  ]
}
```

Each row also has `stats` (events, to-dos, alarms and time zones) and `errors`, capped at the first 200 errors and 200 warnings (`truncated` says if more were found). A URL that can't be fetched gives a row with `fetchError`.

### Limits

This checks structure and the common rules, not every property's value grammar. Recurrence rules (RRULE) and time-zone definitions are not expanded. Calendars can contain personal data (attendees, locations); the Actor doesn't store calendar contents beyond the error messages, which quote at most a date, duration, version or content-type value, never names, addresses or UIDs.

### Integrations

Ready-made files in [`integrations/`](integrations/README.md): a **Microsoft Power Platform custom connector** (Power Automate, Power Apps, Logic Apps, Copilot Studio), **OpenAPI 3** (Azure API Management, Postman, n8n, AI agents), an **Excel / Power BI Power Query** script, a **Google Sheets** function, and curl, Python and JavaScript examples. Apify's own Zapier, Make and n8n apps and its MCP server work too.

### Pricing

Pay per event: $3 per 1,000 results, plus Apify's tiny per-run start fee ($0.00005). See the Pricing tab for the current price.

### Local use

With Node.js 22 or later, run `node cli.js examples/input.json`, or `npm test`. The tests also validate every .ics file the landlorddeadlines.co.uk build produces, when `site/dist` is present.

### Sources

1. [RFC 5545: Internet Calendaring and Scheduling Core Object Specification (iCalendar)](https://www.rfc-editor.org/rfc/rfc5545). Accessed 3 October 2026.

[1]: https://www.rfc-editor.org/rfc/rfc5545

# Actor input Schema

## `icsText` (type: `string`):

The contents of one .ics file, up to 5 MB.

## `urls` (type: `array`):

Up to 50 public http, https or webcal URLs of .ics files or feeds. Each is fetched once (5 MB limit).

## Actor input object example

```json
{
  "icsText": "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Example//EN\r\nBEGIN:VEVENT\r\nUID:1@example.com\r\nDTSTAMP:20261003T000000Z\r\nDTSTART;VALUE=DATE:20261215\r\nDTEND;VALUE=DATE:20261215\r\nSUMMARY:Registration opens; West Midlands\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"
}
```

# Actor output Schema

## `result` (type: `string`):

No description

## `output` (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 = {
    "icsText": `BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//EN
BEGIN:VEVENT
UID:1@example.com
DTSTAMP:20261003T000000Z
DTSTART;VALUE=DATE:20261215
DTEND;VALUE=DATE:20261215
SUMMARY:Registration opens; West Midlands
END:VEVENT
END:VCALENDAR`
};

// Run the Actor and wait for it to finish
const run = await client.actor("landlordtools/ics-calendar-validator").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 = { "icsText": """BEGIN:VCALENDAR\r
VERSION:2.0\r
PRODID:-//Example//EN\r
BEGIN:VEVENT\r
UID:1@example.com\r
DTSTAMP:20261003T000000Z\r
DTSTART;VALUE=DATE:20261215\r
DTEND;VALUE=DATE:20261215\r
SUMMARY:Registration opens; West Midlands\r
END:VEVENT\r
END:VCALENDAR\r
""" }

# Run the Actor and wait for it to finish
run = client.actor("landlordtools/ics-calendar-validator").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 '{
  "icsText": "BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\nPRODID:-//Example//EN\\r\\nBEGIN:VEVENT\\r\\nUID:1@example.com\\r\\nDTSTAMP:20261003T000000Z\\r\\nDTSTART;VALUE=DATE:20261215\\r\\nDTEND;VALUE=DATE:20261215\\r\\nSUMMARY:Registration opens; West Midlands\\r\\nEND:VEVENT\\r\\nEND:VCALENDAR\\r\\n"
}' |
apify call landlordtools/ics-calendar-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,landlordtools/ics-calendar-validator"
        }
    }
}
```

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/CQc9ptUxBZZzlys2n/builds/grSUjVKKG7P1A8TQd/openapi.json
