# Endoflife Date Scraper (`kawsar/endoflife-date-scraper`) Actor

Track software lifecycle and end-of-support dates instantly. Filter by product, version, or upcoming EOL windows and export clean JSON, CSV, or Excel dat

- **URL**: https://apify.com/kawsar/endoflife-date-scraper.md
- **Developed by:** [Kawsar](https://apify.com/kawsar) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 results

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

### Product Lifecycle Scraper: EOL Dates for Software Versions

<p align="center">
  <img src="https://imgur.com/UKjouan.png" alt="Product Lifecycle" style="max-width:100%; border-radius:14px; width:680px;" />
</p>

Track end-of-life and end-of-support dates across software versions without maintaining a manual spreadsheet. Pick your preferred mode, set an item limit, and export clean data directly to JSON, CSV, or Excel.

### Use Cases

- **Release tracking**: Keep tabs on Python or Node.js release cycles and see exactly when security support ends.
- **Dependency review**: Paste a list of software names and pull cycle information in a single run.
- **Patch windows**: Compare `latest` and `latestReleaseDate` before you freeze a production build.
- **Inventory cleanup**: Extract all available product identifiers, then run a second pass on the ones your stack depends on.
- **EOL-soon report**: Automatically filter for software versions whose end-of-life dates fall within a specific timeframe (e.g., the next 180 days).
- **Scheduled exports**: Set up automated runs on a timer and download fresh CSV or Excel reports straight to your workflow.

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `mode` | string | `all_products` | Choose from `all_products`, `product_cycles`, `single_cycle`, or `eol_soon`. |
| `products` | array | python, nodejs | Slugs for `product_cycles`, `single_cycle`, and `eol_soon` (one per line). Ignored when mode is set to `all_products`, which loads every product. |
| `cycles` | array | 3.12 | Cycle names for `single_cycle`. Each product gets paired with each cycle. |
| `eolWithinDays` | integer | 180 | In `eol_soon` mode, keeps cycles whose EOL date is today or within this many days ahead. |
| `maxItems` | integer | 100 | Data-row limit (maximum 1000). Error rows do not count toward this cap. |
| `requestDelaySecs` | number | 1 | Pause between requests in seconds to keep execution smooth and steady. |
| `timeoutSecs` | integer | 300 | Stop starting new requests after this duration (maximum 3600 seconds). |
| `requestTimeoutSecs` | integer | 30 | Timeout limit for individual requests. |
| `proxyConfiguration` | object | Off (`useApifyProxy` false) | Optional proxy configuration. |

#### Example Input

```json
{
  "mode": "product_cycles",
  "products": ["python", "nodejs"],
  "maxItems": 100,
  "eolWithinDays": 180,
  "requestDelaySecs": 1,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": { "useApifyProxy": false }
}

```

### Extracted Data Output

Extracted records are stored directly in the default dataset. A standard Python cycle output looks like this:

```json
{
  "product": "python",
  "cycle": "3.15",
  "releaseDate": "2026-10-09",
  "eol": "2031-10-31",
  "latest": "3.15.0",
  "latestReleaseDate": "2026-10-09",
  "lts": false,
  "support": "2028-10-09",
  "scraped_at": "2026-10-12T00:00:00Z"
}

```

| Field | Type | Description |
| --- | --- | --- |
| `product` | string | The software product name or slug requested. |
| `cycle` | string | Release cycle version. |
| `releaseDate` | string | Cycle release date. |
| `eol` | string or boolean | EOL date, or a boolean indicator if applicable. |
| `latest` | string | Latest patch version available. |
| `latestReleaseDate` | string | Release date of the latest patch. |
| `lts` | boolean or string | LTS (Long Term Support) flag or end date string. |
| `support` | string or boolean | End date of active support. |
| `scraped_at` | string | UTC timestamp when the record was processed. |
| `error` | string | Returned on failed requests with status details and messaging. |

`all_products` mode loads every product on endoflife.date and exports one fully populated row per release cycle (cycle, releaseDate, eol, latest, support), up to `maxItems`. `product_cycles` mode does the same for only the slugs you list. `single_cycle` mode maps specific products to selected cycle versions. `eol_soon` filters results to dates falling between today and today plus `eolWithinDays`.

Duplicate `product|cycle` combinations in the same run are automatically deduplicated.

### How It Works

1. Processes your input preferences and constructs the list of requested items.
2. Executes requests sequentially with your custom User-Agent header.
3. Pauses according to your configured `requestDelaySecs` settings between tasks.
4. Handles unexpected errors gracefully with exponential backoff retries.
5. Processes results as a stream and trims items when reaching `maxItems`.
6. Non-200 responses or malformed data are logged as error entries while allowing the overall run to finish smoothly.
7. Results are pushed to the dataset in batched outputs.

### FAQ

**Can I export data as CSV or Excel?**
Yes! You can export your run results from the dataset as JSON, CSV, or Excel directly from the Apify platform.

**What happens if a product name is invalid?**
If a software slug isn't found, the scraper outputs a clean error row with status details without stopping or crashing the entire run.

**How many rows can I pull per run?**
`maxItems` defaults to 100 rows and can be increased up to a maximum of 1,000 per run.

**Which dates are included in `eol_soon` mode?**
It filters for cycles where `eol` is an active date ranging from today through today plus your specified `eolWithinDays` setting (default: 180 days). Passed dates and boolean values are excluded.

### Trademark Notice

Product names, logos, and trademarks mentioned in this documentation belong to their respective owners. Their inclusion is strictly for identification purposes and does not imply affiliation, endorsement, or sponsorship.

### Disclaimer

This scraper is an independent software tool designed for automated data processing. Users are responsible for ensuring that their data collection activities comply with applicable terms of service and usage regulations.

### Is Web Scraping Legal?

This Actor only collects publicly available data without bypassing access controls. Scraping public data is generally legal, but how you use it matters:

- **Personal data:** If results include personal details, data privacy regulations such as GDPR or CCPA may apply. Only collect and process personal data when you have a clear legal ground or legitimate interest.
- **Copyright:** Content and intellectual property may be protected by copyright law. Avoid republishing full copyrighted materials without proper permissions.
- **Terms of use:** Respect website usage terms, request limits, and attribution guidelines.
- **Legal advice:** This summary is provided for general informational purposes and does not constitute formal legal advice. Consult legal counsel if you have specific regulatory concerns.

Learn more by reading Apify's full guide: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

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

all_products loads every product on endoflife.date with its full release-cycle data (cycle, releaseDate, eol, latest, support) so rows are populated, not blank. product_cycles loads release cycles for only the slugs you list. single_cycle loads one cycle per product. eol_soon keeps cycles whose EOL date falls within eolWithinDays.

## `products` (type: `array`):

Product slugs from endoflife.date, one per line. Used by product_cycles, single_cycle, and eol_soon. Ignored for all_products. Example: python.

## `cycles` (type: `array`):

Release cycle names for single_cycle, one per line. Each product is requested with each cycle. Example: 3.12.

## `eolWithinDays` (type: `integer`):

For eol_soon, keep a cycle when its EOL date is today or at most this many days ahead. Past dates and boolean EOL flags are left out. Default 180.

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

Maximum data rows to save this run. Hard cap is 1000. Error rows do not count toward this limit.

## `requestDelaySecs` (type: `number`):

Seconds to wait between API calls. Default is 1 so the run stays near one request per second. The public API does not publish a rate limit.

## `userAgent` (type: `string`):

User-Agent sent on every request. Keep an app name and a contact address so the host can tell who is calling.

## `timeoutSecs` (type: `integer`):

Stop starting new requests after this many seconds and keep rows already collected. Default 300. Maximum 3600.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for one endoflife.date response before treating that call as failed. Default 30 seconds.

## `proxyConfiguration` (type: `object`):

Optional proxy for API requests. Leave useApifyProxy off. The public JSON endpoints do not need a proxy.

## Actor input object example

```json
{
  "mode": "all_products",
  "products": [
    "python",
    "nodejs"
  ],
  "cycles": [
    "3.12"
  ],
  "eolWithinDays": 180,
  "maxItems": 100,
  "requestDelaySecs": 1,
  "userAgent": "",
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Product, cycle, release date, EOL, latest patch, LTS, support, and source URL.

## `errors` (type: `string`):

Failed API requests with URL, HTTP status, and message.

## `dataset` (type: `string`):

Every row from the run, without a table view applied.

# 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 = {
    "products": [
        "python",
        "nodejs"
    ],
    "cycles": [
        "3.12"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kawsar/endoflife-date-scraper").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 = {
    "products": [
        "python",
        "nodejs",
    ],
    "cycles": ["3.12"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("kawsar/endoflife-date-scraper").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 '{
  "products": [
    "python",
    "nodejs"
  ],
  "cycles": [
    "3.12"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call kawsar/endoflife-date-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kawsar/endoflife-date-scraper"
        }
    }
}
```

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/ickC8fK6A2K3tiFJC/builds/ab5fUBsViPkq9wTHb/openapi.json
