# Agent Output Gate - PII, Link & Hallucination Check (`apricot_blackberry/agent-output-gate`) Actor

A safety gate between your AI agent and the send button. Scans a draft for PII and leaked secrets (Luhn-checked cards, API keys), broken links, and claims not supported by your source URLs, then returns pass/fail, flagged excerpts, and PII-redacted text.

- **URL**: https://apify.com/apricot\_blackberry/agent-output-gate.md
- **Developed by:** [Creator Fusion](https://apify.com/apricot_blackberry) (community)
- **Categories:** AI, Developer tools
- **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/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

## Agent Output Gate — Pre-Send Safety Check for AI Agents

**Your agent drafts a message. Before it actually sends or publishes, run the draft through this gate.**
One call in, one typed JSON verdict out: PII/secret leaks, dead links, and claims your sources don't support — caught before they ship.

Built for autonomous agents and pipelines. Deterministic checks (no LLM in the loop), success-only billing, MCP-ready.

### What it checks

1. **PII & secrets** — emails, phone numbers, SSN-formatted numbers, credit-card numbers (validated by the **Luhn** algorithm, so random 16-digit strings don't false-positive), and common API-key/token shapes (`sk-…`, `AKIA…`, `ghp_…`, `AIza…`, `Bearer …`). Each is reported with a **masked** excerpt.
2. **Links** — every URL in the draft is fetched (HEAD then GET, short timeout); anything dead or non-2xx/3xx is flagged.
3. **Claim-vs-source** *(only when `sourceUrls` given)* — sentences containing specific **numbers, quoted strings, or named entities** that appear in **none** of your ground-truth sources are flagged as possible hallucinations.
4. **Basic policy** — profanity and obvious secret leakage.

Output is **one row**: `pass`, `flagCount`, `flags[]` (`type`, `severity`, `excerpt`, `reason`), and `redactedText` (a copy of the draft with PII/secrets masked). `pass` is `true` only when zero flags were raised.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `text` | string | ✅ | The draft output to check. |
| `sourceUrls` | string\[] | | Ground-truth sources; enables claim-vs-source checking. |
| `checkLinks` | boolean | | Fetch and validate links in the draft. Default `true`. |
| `proxyConfiguration` | object | | Fallback proxy for link/source fetches only (caller-billed). Direct connection is tried first. |

### Output row

```json
{
  "pass": false,
  "flagCount": 3,
  "flags": [
    { "type": "email", "severity": "medium", "excerpt": "ja******om", "reason": "Email address present in draft output." },
    { "type": "credit-card", "severity": "high", "excerpt": "45********11", "reason": "Luhn-valid credit-card number present in draft output." },
    { "type": "dead-link", "severity": "medium", "excerpt": "http://example.com/definitely-404", "reason": "Link returned HTTP 404." }
  ],
  "redactedText": "… reach me at [REDACTED_EMAIL] …",
  "checkedAt": "2026-08-19T00:00:00.000Z"
}
```

### Integration

#### MCP (agent tool call)

Point your MCP client at the Apify MCP server and call the actor by name `apricot_blackberry/agent-output-gate` with:

```json
{ "text": "…draft…", "sourceUrls": ["https://docs.example.com/pricing"], "checkLinks": true }
```

#### curl (run and get the verdict row)

```bash
curl -s -X POST "https://api.apify.com/v2/acts/apricot_blackberry~agent-output-gate/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"text":"Contact me at a@b.com http://example.com/definitely-404","checkLinks":true}'
```

#### JavaScript (apify-client)

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('apricot_blackberry/agent-output-gate').call({
    text: draft,
    sourceUrls: ['https://docs.example.com/pricing'],
    checkLinks: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
if (!items[0].pass) throw new Error(`Draft failed gate: ${items[0].flagCount} flag(s)`);
```

#### Python (apify-client)

```python
from apify_client import ApifyClient
client = ApifyClient(token)
run = client.actor("apricot_blackberry/agent-output-gate").call(run_input={
    "text": draft,
    "sourceUrls": ["https://docs.example.com/pricing"],
    "checkLinks": True,
})
row = next(client.dataset(run["defaultDatasetId"]).iterate_items())
if not row["pass"]:
    raise RuntimeError(f"Draft failed gate: {row['flagCount']} flag(s)")
```

### Pricing

Pay-per-event. One `actor-start` fee per run, plus one `check` event per completed check. Failed runs are not billed for the check. Link/source-fetch proxy traffic, if used, is billed to your Apify account.

### Notes

- Checks are deterministic and self-contained — no LLM, no data sent anywhere except the link/source fetches you enable.
- Claim-vs-source is a heuristic recall aid (numbers/quotes/named-entities), not a semantic fact-checker; treat `unsupported-claim` flags as "verify this", not "definitely wrong".

# Actor input Schema

## `text` (type: `string`):

The agent's DRAFT output to safety-check before it is sent or published. Plain text; markdown is fine. This is the only required field.

## `sourceUrls` (type: `array`):

Optional. URLs of authoritative sources the draft's claims should be grounded in. When provided, sentences containing specific numbers, quoted strings, or named entities that appear in NONE of these sources are flagged as possible hallucinations.

## `checkLinks` (type: `boolean`):

Extract every URL in the draft and fetch it (HEAD then GET, short timeout); flag any that are dead or return a non-2xx/3xx status. Turn off to skip all outbound link fetching.

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

Proxy used only as a fallback for link/source fetches that fail directly (link checking connects directly first, which is free). Proxy traffic is billed to your Apify account. No proxy is used for the PII/secret/claim analysis itself.

## Actor input object example

```json
{
  "text": "Hi team, reach me at jane.doe@example.com or 415-555-0142. Full docs: http://example.com/definitely-404-page. Q2 revenue grew 42% year over year.",
  "sourceUrls": [],
  "checkLinks": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `verdict` (type: `string`):

The single verdict row for the checked draft (pass, flagCount, flags, redactedText).

# 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 = {
    "text": "Hi team, reach me at jane.doe@example.com or 415-555-0142. Full docs: http://example.com/definitely-404-page. Q2 revenue grew 42% year over year."
};

// Run the Actor and wait for it to finish
const run = await client.actor("apricot_blackberry/agent-output-gate").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 = { "text": "Hi team, reach me at jane.doe@example.com or 415-555-0142. Full docs: http://example.com/definitely-404-page. Q2 revenue grew 42% year over year." }

# Run the Actor and wait for it to finish
run = client.actor("apricot_blackberry/agent-output-gate").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 '{
  "text": "Hi team, reach me at jane.doe@example.com or 415-555-0142. Full docs: http://example.com/definitely-404-page. Q2 revenue grew 42% year over year."
}' |
apify call apricot_blackberry/agent-output-gate --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apricot_blackberry/agent-output-gate"
        }
    }
}

```

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/j6M1mHEdxxcLV6ksB/builds/mO8XvAY5g8Hem4Jm1/openapi.json
