# CSV Quality Validator - Batch Schema Report (`tidytools/csv-quality-validator`) Actor

Validate pasted CSV tables with Frictionless. Row, field and error codes only; no raw CSV or cell values in reports. Completed checks are billable even when CSV has errors; input and technical failures are free.

- **URL**: https://apify.com/tidytools/csv-quality-validator.md
- **Developed by:** [Yukai Lin](https://apify.com/tidytools) (community)
- **Categories:** Developer tools, Automation, Business
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 validated tables

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

## CSV Quality Validator

### What it does

Validate 1–20 pasted CSV tables with Frictionless. This Actor accepts CSV text only: no URLs, uploads, paths, remote schemas, profiles, references, or plugins. Each CSV is limited to 256 KiB and the entire input to 1 MiB. A table can have an optional schema with field `name`, `type` (`string`, `integer`, `number`, `date`), `required` and `unique`.

### How to use

Paste one or more CSV strings into `tables`, give each table a short name, and optionally supply a field schema. Run the Actor and read one Dataset report per table plus the `SUMMARY` key-value record. `valid:false` means the quality check completed and found data errors; `success:false` means the input or check failed.

### Input example

```json
{"tables":[{"name":"orders.csv","csvText":"id,total\n1,12.50\n","schema":{"fields":[{"name":"id","type":"integer","required":true,"unique":true},{"name":"total","type":"number"}]}}]}
```

### Output example

The Dataset has one report per table: `inputIndex`, `name`, `valid`, `errorCount`, `errors` (at most 100 `{rowNumber,fieldName,code}` entries), `truncatedErrors`, `success`, `charged`, and `errorType`. `SUMMARY` gives `checked`, `invalidData`, `invalidInput`, `technicalFailures`, `charged`, `table-validated`, `status`, and `interruptedClaims`.

For the input above, a successful check can return `{"inputIndex":1,"name":"orders.csv","valid":true,"errorCount":0,"errors":[],"truncatedErrors":0,"success":true,"charged":true,"errorType":null}` and `SUMMARY` with `"table-validated":1` when one event is charged.

### Pricing

A completed, saved check emits one candidate `table-validated` event, **including CSVs with duplicate headers, missing cells, type errors, or failed constraints** (`valid:false`, `success:true`, `charged:true`). Blank/oversized/invalid input, a failed runner, or a report that cannot be saved is free. The candidate event and its price require owner approval before publication. The pricing file uses a **provisional $0.005/table** for margin modelling, not an approved public price.

### Limitations

Raw CSV and cell values are not written to logs or reports. Only the table name and error locations/codes are kept in Dataset; the raw CSV is read only from the run input and is not copied to another store. A small progress record holds hashes and aggregate counts. It claims a table before the billed Dataset write, so a restart cannot bill it twice. A restart during the write leaves an `INTERRUPTED` summary with `interruptedClaims`; that table is not retried automatically.

Source and security: Frictionless [validation guide](https://framework.frictionlessdata.io/docs/guides/validating-data) and [security guide](https://framework.frictionlessdata.io/docs/advanced/security.html), checked 2026-10-27. Frictionless is pinned to 5.21.0 (MIT). The runner uses in-memory rows, `trusted=False`, no caller-provided descriptor/path, disabled sockets, a temporary working directory and an environment without secrets.

### FAQ

**Is invalid CSV data billed?** Yes, when validation completes and its report is saved. Blank or oversized input and technical failures are free. **Can I submit a file URL or remote schema?** No; paste CSV text and use the restricted local field schema.

### Local tests

```sh
npm test
python -m pip install -r requirements.txt
python -m unittest discover -s test -p 'test_*.py'
```

### Q1 plan

The invalid and valid capital CSVs and the single-column `header` sample are from the Frictionless validation guide, checked 2026-10-27. The mixed case adds an over-limit label to exercise free input rejection.

```q1
{"actor":"csv-quality-validator","cases":[{"name":"Official invalid capitals","input":{"tables":[{"name":"capital-invalid.csv","csvText":"id,name,name\n1,London,Britain\n2,Berlin,Germany\n8,Warsaw\nx,Tokio,Japan,review\n"}]},"expect":"1 row valid=false/success=true/charged=true and duplicate-label; table-validated=1."},{"name":"Single-column values from Frictionless guide","input":{"tables":[{"name":"header.csv","csvText":"header\n1\n2\n3\n","schema":{"fields":[{"name":"header","type":"integer"}]}}]},"expect":"1 row valid=true/success=true/charged=true/errorCount=0; table-validated=1."},{"name":"Official valid capitals with schema","input":{"tables":[{"name":"capital-valid.csv","csvText":"id,name\n1,London\n2,Berlin\n3,Paris\n4,Madrid\n5,Rome\n","schema":{"fields":[{"name":"id","type":"integer","required":true,"unique":true},{"name":"name","type":"string"}]}}]},"expect":"1 row valid=true/success=true/charged=true/errorCount=0; table-validated=1."},{"name":"Mixed valid and over-limit label","input":{"tables":[{"name":"capital-valid.csv","csvText":"id,name\n1,London\n2,Berlin\n"},{"name":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","csvText":"id,name\n1,London\n"}]},"expect":"First row valid=true/success=true/charged=true; second success=false/charged=false/errorType=invalid_input; table-validated=1."}]}
```

# Actor input Schema

## `tables` (type: `array`):

Each item: {"name":"orders.csv","csvText":"id,amount\n1,12.5\n"}. Optional schema: {"fields":\[{"name":"id","type":"integer","required":true,"unique":true}]}. No URLs, file paths or references. Each CSV <=256 KiB; entire input <=1 MiB.

## Actor input object example

```json
{
  "tables": [
    {
      "name": "capital-invalid.csv",
      "csvText": "id,name,name\n1,London,Britain\n2,Berlin,Germany\n8,Warsaw\nx,Tokio,Japan,review\n"
    }
  ]
}
```

# Actor output Schema

## `reports` (type: `string`):

No description

## `summary` (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 = {
    "tables": [
        {
            "name": "capital-invalid.csv",
            "csvText": "id,name,name\n1,London,Britain\n2,Berlin,Germany\n8,Warsaw\nx,Tokio,Japan,review\n"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidytools/csv-quality-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 = { "tables": [{
            "name": "capital-invalid.csv",
            "csvText": """id,name,name
1,London,Britain
2,Berlin,Germany
8,Warsaw
x,Tokio,Japan,review
""",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("tidytools/csv-quality-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 '{
  "tables": [
    {
      "name": "capital-invalid.csv",
      "csvText": "id,name,name\\n1,London,Britain\\n2,Berlin,Germany\\n8,Warsaw\\nx,Tokio,Japan,review\\n"
    }
  ]
}' |
apify call tidytools/csv-quality-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tidytools/csv-quality-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/zkLxpSeyabtCBD1kT/builds/u5Q1aakHooXwixzXM/openapi.json
