# Username Monitor: Availability Checker + Recurring Alerts (`shipsatnight/username-monitor`) Actor

Bulk username availability checking across GitHub, GitLab, Bluesky, Farcaster, npm, PyPI, crates.io, Docker Hub, Spotify, SoundCloud, Vimeo, YouTube, and X. Optional monitor mode alerts via webhook/Slack when a username's status changes.

- **URL**: https://apify.com/shipsatnight/username-monitor.md
- **Developed by:** [Donovan](https://apify.com/shipsatnight) (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 $0.50 / 1,000 platform checkeds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Username Monitor

Bulk username availability checking across **GitHub, GitLab, Bluesky, Farcaster, npm, PyPI, crates.io, Docker Hub, Spotify, SoundCloud, Vimeo, YouTube, and X** — plus optional **monitor mode**: get alerted when a username's status actually changes, instead of re-checking it by hand.

Built for founders naming a product, brand-protection teams, OSINT researchers, and security teams watching for namespace/typosquat risk on package registries.

### What sets this apart

Every username checker on the Apify Store does a one-shot lookup. None of them do recurring monitoring — verified against the eight closest competitors before building this (easyapi, sync-network, corent1robert, maximedupre, parsebird, maged120, dev00, goat255):

- **Monitor mode.** Pair with an Apify Schedule and this actor remembers the last result per username/platform, diffs against the current check, and only reports (and charges for) an actual status change — available → taken, or taken → available. Nobody else in this category does this.
- **Webhook + Slack alerts, no code required.** Fill in a URL, get a POST when something changes. This is deliberately the same no-code pattern the top competitors in adjacent categories (website-change-monitor actors) already ship — Apify Store buyers are a mix of developers integrating via API and non-technical users configuring alerts through the Console, not developers exclusively.
- **A curated platform list, not a padded one.** The highest-user-count competitor in this category (80+ platforms) is largely a copy of the classic Sherlock OSINT tool's site list — Blip.fm, Periscope, LiveLeak, MySpace, and other platforms that are dead or irrelevant in 2026. Every platform here was hit with a live test today against a known-taken and a known-free username before being included. See "What's not included" below for what got cut and why.
- **A dev-namespace bundle nobody else covers.** npm, PyPI, crates.io, and Docker Hub username/package availability — real typosquat and supply-chain-risk signal for security teams, and genuinely uncontested in this category.

### Platforms

| Platform | Signal | Notes |
|---|---|---|
| `github` | `200` taken / `404` free | |
| `gitlab` | `200` taken / `3xx` free | GitLab redirects unknown handles rather than 404ing them |
| `bluesky` | `200` taken / `400` free | AT Protocol's own `resolveHandle` endpoint, no auth |
| `farcaster` | body-based | Always returns `200` — availability comes from whether the fname registry's `transfers` array is empty |
| `npm` | `200` taken / `404` free | Checks package-name availability, the actual typosquat signal |
| `pypi` | `200` taken / `404` free | |
| `crates_io` | `200` taken / `404` free | Requires a descriptive User-Agent — crates.io rejects generic ones |
| `docker_hub` | `3xx` taken / `404` free | Opposite convention from GitLab — taken usernames redirect, free ones 404 |
| `spotify` | `200` taken / `404` free | |
| `soundcloud` | `200` taken / `404` free | |
| `vimeo` | `200` taken / `404` free | |
| `youtube` | `200` taken / `404` free | Checks the newer `@handle` format |
| `twitter` | `200` taken / `404` free | **Best-effort.** X rate-limits and bot-blocks aggressively at any real volume — confirmed locally, two sequential checks were enough to trigger a `503`. Don't rely on this for bulk or high-frequency monitor-mode use until it's been stress-tested further. |

### What's not included, and why

- **Instagram, TikTok, Twitch, Steam, Pinterest, Roblox** — all tested live today and all return `200` regardless of whether the username exists. They're JS-rendered SPAs that don't 404 at the HTTP level; a real check would need body-text scraping (fragile, breaks on markup changes) or an internal API endpoint that wasn't verified. Not shipping a check that looks like it works but doesn't.
- **Reddit, Ko-fi** — both returned `403` on every request tested today, taken or free. Blocked outright at the HTTP level; would need `impit` or a browser to get past, which is real added cost, not free.
- **Discord** — no public unauthenticated username-check endpoint exists. The only path is the registration flow, which is a captcha-protected multi-field POST, not something a public multi-tenant actor can safely probe.

### Input

```json
{
  "usernames": ["shipsatnight"],
  "platforms": [],
  "monitorMode": true,
  "monitorName": "brand-watch",
  "webhookUrl": "",
  "slackWebhookUrl": ""
}
```

| Field | Type | Default | What it does |
|---|---|---|---|
| `usernames` | string\[] | required | With or without a leading `@`. Duplicates removed automatically. |
| `platforms` | string\[] | all | Which platforms to check. Omit to check everything. |
| `monitorMode` | boolean | `false` | Compare this run against the last run under the same `monitorName`; report and alert only on changes. |
| `monitorName` | string | `"default"` | Namespaces saved state so multiple monitors don't collide. |
| `webhookUrl` | string | — | POSTed a JSON payload on any detected status change. |
| `slackWebhookUrl` | string | — | Posts a formatted Slack message on any detected status change. |

### Output

One record per username in the default dataset:

```json
{
  "username": "shipsatnight",
  "checked_at": "2026-08-04T14:00:00.000Z",
  "platforms": [
    { "platform": "github", "status": "taken", "profile_url": "https://github.com/shipsatnight" },
    { "platform": "npm", "status": "available", "profile_url": null }
  ],
  "changed_since_last_run": [
    { "platform": "npm", "previous_status": "taken", "current_status": "available" }
  ]
}
```

`changed_since_last_run` is only present in monitor mode, and only when something actually changed. A run-level summary (usernames processed, checks/alerts charged, whether the run stopped early on a spending cap) is written to the key-value store under `RUN_SUMMARY`.

### Monitor mode mechanics

Apify actors don't run continuously — monitor mode is a Schedule (cron, configured in the Console, no code) that re-runs this actor periodically. Each run loads the last known status per username/platform from a **named** key-value store (not the run-scoped default one — the default store doesn't survive between separate Schedule-triggered runs), diffs it against the current check, and only reports/charges/alerts on an actual flip. A failed check (`unknown`) never counts as a change in either direction, so a transient network blip doesn't fire a false alert.

### Pricing

Pay-per-event: $0.00005 actor start, $0.0005 per platform successfully checked, $0.002 per alert fired in monitor mode. Failed/unknown checks aren't charged — matches the norm this category has already converged on (competitors explicitly advertise "rate-limited or unknown results are never charged").

### Status

Built and locally verified — delta detection and webhook delivery confirmed across simulated status-flip test runs. Not yet pushed, monetized, or published to the Apify Store.

# Actor input Schema

## `usernames` (type: `array`):

Usernames to check, with or without a leading @. Duplicates are removed automatically.

## `platforms` (type: `array`):

Which platforms to check. Leave empty to check all of them.

## `monitorMode` (type: `boolean`):

When enabled, compares this run's results against the last run under the same Monitor name and reports/alerts only on status changes (e.g. taken → available). Pair with an Apify Schedule for recurring checks.

## `monitorName` (type: `string`):

Namespaces the saved state so multiple monitors don't collide. Only used when Monitor mode is on.

## `webhookUrl` (type: `string`):

POSTed a JSON payload with the username, platform, and status change whenever Monitor mode detects one.

## `slackWebhookUrl` (type: `string`):

Posts a formatted message to Slack whenever Monitor mode detects a status change.

## Actor input object example

```json
{
  "usernames": [
    "shipsatnight"
  ],
  "platforms": [],
  "monitorMode": false,
  "monitorName": "default"
}
```

# Actor output Schema

## `usernameReports` (type: `string`):

One record per username, with a per-platform availability result and (in Monitor mode) any status changes since the last run.

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

Counts of usernames processed, checks/alerts charged, and charge-limit status for this run.

# 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 = {
    "usernames": [
        "shipsatnight"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("shipsatnight/username-monitor").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 = { "usernames": ["shipsatnight"] }

# Run the Actor and wait for it to finish
run = client.actor("shipsatnight/username-monitor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "usernames": [
    "shipsatnight"
  ]
}' |
apify call shipsatnight/username-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=shipsatnight/username-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/7lQQAKkY7Gr6EcquZ/builds/dFG84GK5PRoKjxoDn/openapi.json
