# Domain Expiry Watch — Early Signal Before a Domain Drops (`oswaldocarabano/zone-exit-watch`) Actor

Watches registry zone files for domains that dropped out, with how many days they have been absent. Zone exit happens about 35 days before release, so this is domain expiration monitoring at its earliest point: an early watchlist, not a list of expired domains you can buy today.

- **URL**: https://apify.com/oswaldocarabano/zone-exit-watch.md
- **Developed by:** [Oswaldo Carabano](https://apify.com/oswaldocarabano) (community)
- **Categories:** Developer tools, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

## Domain Expiry Watch — Early Signal Before a Domain Drops

Domains that disappeared from the registries' zone files, with how many days they have
been absent.

Leaving the zone happens roughly **35 days before** a domain is actually released, so
this is an early warning — a shortlist to watch, not a list of domains you can buy.

### Coverage

**1,075 gTLDs**, including `.com`, `.net`, `.org`, `.info`, `.biz`, `.xyz`, `.top`,
`.shop`, `.online`, `.site`, `.store`, `.app`, `.dev` and `.cloud` — **255,631,856
delegated domains**, counted from the zone files themselves and refreshed daily.

Coverage is real but it is not evenly spread, and you should know the shape of it
before you rely on it: `.com` alone is 166 million of that total, and while all 1,075
TLDs are included, 481 of them hold fewer than a thousand domains each. Breadth helps
you catch something in an obscure TLD; it is not 1,075 equally busy namespaces.

**Not covered:** `.io`, `.ai`, `.co`, `.me`, `.tv`, `.cc` and every other country-code
TLD. These are not available from ICANN's zone file service at any price — they are run
outside ICANN's contracts. They are also exactly the TLDs a startup expects, so we say
it here rather than letting you find out from an empty result.

**What a zone file does not contain, and no run will ever return:** the registrant,
their email, the registrar, the registration date, the expiry date, or the domain's own
A, MX and TXT records. Any tool promising those needs a different source, and at scale
that source is prohibited by the agreement behind this data.

### Input

Every run is anchored on something you provide. There is no way to ask this Actor for
the whole namespace, and that is a design decision rather than a limitation: the data
agreement behind it forbids handing over a substantial portion of a zone, so the
product simply has no shape that could.

See **Example runs** below for fifteen worked inputs.

### Output

| Field | Meaning |
|---|---|
| `domain` | The domain that left the zone |
| `tld` | Its top-level domain |
| `exited_on` | The date of the first snapshot where it was missing |
| `days_absent` | How many days it has been missing since |
| `last_nameservers` | Where it delegated before it left |
| `dns_provider` | Who ran its DNS, inferred from those nameservers |
| `parked_for_sale` | True when it was already sitting on a parking or sale service before it left. A parked domain leaving the zone is a much firmer drop candidate than one that was in active use |

### Reading the results

🔴 **This Actor is deliberately not called "expired domains", and that matters.**

More than half the domains that leave the zone **never drop**. They come back: a
renewal that landed late, a nameserver misconfiguration, a registrar suspension that
got resolved. If we called this "expired domains" we would be selling you a list where
most rows are wrong.

What we sell instead is the **zone exit event with an age**, and the `minDaysAbsent`
filter is the control that turns a noisy early signal into a useful one:

| `minDaysAbsent` | What you get |
|---|---|
| 0 | Includes domains that left the zone today. The earliest possible signal, and the noisiest |
| 1 | Everything from yesterday back, including the renewals that come back tomorrow |
| 7 | Most transient problems have resolved themselves |
| 30 | Domains genuinely heading for release |

**The zone event itself is 100% reliable.** This domain was in yesterday's snapshot and
is not in today's. What is uncertain is what it means, and that uncertainty is the
reason for the filter rather than something we hide.

**We do not query WHOIS or RDAP to resolve the ambiguity**, and we will not: querying
registries at scale is prohibited by the agreement that gives us this data at all.

**`dns_provider` says who runs the DNS, not what the site is built with.** The
nameserver identifies the DNS operator for 69% of domains, but a domain on Cloudflare
can be running anything. Website platforms are configured with A and CNAME records,
which a zone file does not contain, so we cannot see them and we do not guess.

**An empty result** means nothing left the zone matching your filters, or nothing has
been absent long enough. It only costs the $0.00001 start fee.

### Example runs

**1. Find domains dropping in a niche TLD**

```json
{
  "tld": [
    "bank"
  ],
  "minDaysAbsent": 30,
  "days": 60,
  "maxResults": 500
}
```

**2. Check whether any of your own domains lapsed**

```json
{
  "contains": [
    "shopify"
  ],
  "minDaysAbsent": 1,
  "days": 7,
  "maxResults": 100
}
```

**3. Find short domains leaving the registry zone**

```json
{
  "contains": [
    "zy"
  ],
  "tld": [
    "com"
  ],
  "minDaysAbsent": 21,
  "days": 45,
  "maxResults": 1000
}
```

**4. Track crypto domains going quiet**

```json
{
  "contains": [
    "nft",
    "token"
  ],
  "minDaysAbsent": 14,
  "days": 30,
  "maxResults": 1000
}
```

**5. Watch a competitor releasing domain names**

```json
{
  "contains": [
    "northwind"
  ],
  "minDaysAbsent": 7,
  "days": 30,
  "maxResults": 200
}
```

**6. Monitor domains dropping out of a busy TLD**

```json
{
  "tld": [
    "shop"
  ],
  "minDaysAbsent": 30,
  "days": 60,
  "maxResults": 5000
}
```

**7. High-confidence domain drop candidates**

```json
{
  "contains": [
    "travel"
  ],
  "minDaysAbsent": 45,
  "days": 90,
  "maxResults": 2000
}
```

**8. Research view of domains leaving a TLD**

```json
{
  "tld": [
    "xyz"
  ],
  "minDaysAbsent": 1,
  "days": 3,
  "maxResults": 5000
}
```

**9. Find abandoned brand domains in shop and store**

```json
{
  "contains": [
    "shop",
    "store"
  ],
  "minDaysAbsent": 30,
  "days": 90,
  "maxResults": 2000
}
```

**10. Monitor a client managed domains for lapses**

```json
{
  "contains": [
    "agency"
  ],
  "minDaysAbsent": 1,
  "days": 14,
  "maxResults": 100
}
```

**11. Find dropping domains with a city keyword**

```json
{
  "contains": [
    "madrid"
  ],
  "minDaysAbsent": 21,
  "days": 60,
  "maxResults": 1000
}
```

**12. Track a failed startup domain assets**

```json
{
  "contains": [
    "startup"
  ],
  "minDaysAbsent": 7,
  "days": 60,
  "maxResults": 200
}
```

**13. Find dictionary word domains dropping in app**

```json
{
  "tld": [
    "app"
  ],
  "minDaysAbsent": 30,
  "days": 90,
  "maxResults": 2000
}
```

**14. Weekly conservative domain drop digest**

```json
{
  "contains": [
    "fintech"
  ],
  "minDaysAbsent": 30,
  "days": 45,
  "maxResults": 1000
}
```

**15. Quarterly study of domain drops in one TLD**

```json
{
  "tld": [
    "online"
  ],
  "minDaysAbsent": 45,
  "days": 90,
  "maxResults": 5000
}
```

### Pricing

**$0.00001 to start, then $0.002 per zone exit** — about **$2 per 1,000 results**.

Same price as the new-delegations Actor and for the same reason: it is built to be
scheduled daily with a narrow filter, where most runs cost almost nothing.

Raise `minDaysAbsent` before you raise `maxResults`. A run with `minDaysAbsent: 1`
returns a lot of rows that will resolve themselves by tomorrow, and you pay for every
one of them.

### Data source

> 🛡️ **Sourced from the Registry Operators' own zone files**, obtained through ICANN's
> Centralized Zone Data Service under agreement with those operators. ICANN does not
> endorse, sponsor or review this Actor.

Built for security research, brand protection and domain analytics. The access behind
this data was granted one TLD at a time, which is why the coverage is what it is.

### Support

Found a domain the Actor missed, or a row that looks wrong? Open an issue on the Actor
page with the exact input you used. Zone data is refreshed once a day, so a domain
delegated this morning may not appear until tomorrow's snapshot.

# Actor input Schema

## `contains` (type: `array`):

Only return exits whose name contains one of these words. Either this or a TLD filter is required.

## `tld` (type: `array`):

Restrict to these TLDs, without the dot.

## `minDaysAbsent` (type: `integer`):

Only show domains missing from the zone for at least this many days. Use 0 to include domains that left the zone today. Higher values mean fewer false alarms - read the README before trusting a low value.

## `days` (type: `integer`):

How many days of daily snapshots to search. Required and capped at 90 — there is no "since forever", by design.

## `maxResults` (type: `integer`):

Hard cap on rows returned. Kept low on purpose so a first run cannot burn your free credit. Raise it deliberately. The service will never return more than 50,000 rows in one run.

## Actor input object example

```json
{
  "contains": [
    "shop"
  ],
  "tld": [],
  "minDaysAbsent": 1,
  "days": 7,
  "maxResults": 100
}
```

# Actor output Schema

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

Watches registry zone files for domains that dropped out, with how many days they have been absent. Zone exit happens about 35 days before release, so this is domain expiration monitoring at its earliest point: an early watchlist, not a list of expired domains you can buy today.

## `runSummary` (type: `string`):

How many rows matched, whether the row cap truncated the answer, and the date of the zone data used. If truncated is true, you are seeing a partial answer.

# 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 = {
    "contains": [
        "shop"
    ],
    "tld": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("oswaldocarabano/zone-exit-watch").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 = {
    "contains": ["shop"],
    "tld": [],
}

# Run the Actor and wait for it to finish
run = client.actor("oswaldocarabano/zone-exit-watch").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 '{
  "contains": [
    "shop"
  ],
  "tld": []
}' |
apify call oswaldocarabano/zone-exit-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,oswaldocarabano/zone-exit-watch"
        }
    }
}
```

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/kUZ3lJL3QojXhoHpU/builds/jC1jQNarygk2eZoQL/openapi.json
