# Concept3D Account Signals (browser) (`sculpted/concept3d-signals`) Actor

Headless-browser account signals for Concept3D: campus-map axe-core error count, map vendor / is-Concept3D-customer, website redesign (Wayback before/after + vision), competitor + CMS fingerprint. One account in -> one signal row out. Orchestrated by Clay Workflows or Deepline.

- **URL**: https://apify.com/sculpted/concept3d-signals.md
- **Developed by:** [Jacob Tuwiner](https://apify.com/sculpted) (community)
- **Categories:** AI
- **Stats:** 3 total users, 2 monthly users, 84.6% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## 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

## Concept3D Signals — Apify actor

The headless-browser half of the Concept3D account-signals build, packaged as one Apify actor so **Clay Workflows (or Deepline) can call it** and merge the result with the native (API/Claygent) signals. This is the "keystone" from `../CLAY-WORKFLOWS-REBUILD-PLAN.md` — it unblocks the three signals Clay can't run natively (axe, map vendor, redesign).

Ported verbatim from the tested prototypes:

- `../scripts/axe/signals.mjs` — competitor/CMS fingerprint, map discovery, map vendor, axe count
- `../scripts/axe/redesign-qa-v2.mjs` — quality-gated Wayback before/after + vision consensus

### What it produces

One account in → one row out (`Actor.pushData`). Fields:

| Field | Signal | Notes |
|---|---|---|
| `axe_core`, `axe_core_bp`, `axe_total_issues`, `axe_over_20` | Campus-map accessibility | `axe_over_20` flags `core+bp > 20` (matches Sam's axe DevTools default). Flip to `core` if her best-practices toggle is OFF — one line in `axeMap()`. |
| `map_url`, `map_vendor`, `is_concept3d_customer` | Map vendor | Vendor read from the *rendered map page* — sole authority for the customer flag. |
| `redesign_likely`, `redesign_reason`, `before_png_url`, `after_png_url` | Website redesign | `YES` only if every good snapshot agrees "major" (conservative). PNGs stored in the run's key-value store. |
| `competitor_vendor`, `current_cms`, `cms_then`, `cms_now`, `cms_changed` | Competitor + CMS | Static multi-page fingerprint. |
| `unitid` | (pass-through) | Enrollment is computed in Clay, not here; kept so the row stays joined. |

**Not here:** enrollment (native Clay → IPEDS HTTP) and construction (Claygent chain). See `../CLAY-BUILD-SPECS.md`.

### Input

Single account (the Clay enrich-node pattern):

```json
{ "domain": "gatech.edu", "school_name": "Georgia Tech" }
```

Optional: `map_url` (pin the map when discovery misses), `signals` (subset of `competitor_cms` / `map_axe` / `redesign`), `accounts` (array, for batch tests).

### Secrets

The redesign vision judge needs an Anthropic key. Set it as an **actor environment variable / secret** named `ANTHROPIC_API_KEY` (Apify console → Actor → Settings → Environment variables, mark *Secret*). Fallback: pass `anthropic_key` in input. Swap the judge to OpenAI for Concept3D's production env (one `fetch` block in `judge()`), per `../config/signals.json`.

### Run locally

```bash
cd deepline/apify-actor
npm install
npx playwright install chromium        # if not already present
npx apify run                          # uses storage/key_value_stores/default/INPUT.json
## results -> storage/datasets/default/*.json ; screenshots -> storage/key_value_stores/default/*.png
```

(For the redesign judge locally: `export ANTHROPIC_API_KEY=...` first, or it returns `no key`.)

### Deploy

```bash
npm i -g apify-cli
apify login                            # needs APIFY_TOKEN (placeholder noted in ../.env)
apify push                            # builds the Docker image on Apify, returns the actor id
```

### Call it from Clay

In the Clay workflow, an **enrich node** runs the actor synchronously and reads the dataset items back. Candidate action: Clay's Apify **"Run Actor (sync, get dataset items)"** integration, or a generic HTTP node hitting:

```
POST https://api.apify.com/v2/acts/<ACTOR_ID>/run-sync-get-dataset-items?token=<APIFY_TOKEN>
Body: { "domain": "{{domain}}", "school_name": "{{school_name}}" }
```

Map the returned fields to the Salesforce columns in `../config/signals.json`. Full node graph in `../CLAY-BUILD-SPECS.md`.

### Calibration carry-over

The one open client dependency from `../MEETING-PRIORITIES.md`: lock `axe_over_20` to Sam's recorded counts + her exact axe settings on 2–3 schools (we track her extension within ±4). Best-practices on/off is the toggle that moves the number most.

# Actor input Schema

## `domain` (type: `string`):

School root domain, e.g. gatech.edu (no scheme/www). Required unless `accounts` is given.

## `school_name` (type: `string`):

Optional label, passed through to the output row.

## `map_url` (type: `string`):

Optional. Pin the campus-map page when auto-discovery misses (e.g. Point Park). If blank, the actor discovers it.

## `unitid` (type: `string`):

Optional pass-through. Enrollment is computed in Clay (native HTTP), not here; included only so the row stays joined.

## `signals` (type: `array`):

Subset to run. Default = all browser signals.

## `accounts` (type: `array`):

Optional. Array of {domain, school\_name?, map\_url?, unitid?} for batch test runs. Overrides the single-account fields above.

## `anthropic_key` (type: `string`):

Fallback only. Prefer setting ANTHROPIC\_API\_KEY as an actor environment secret. Used by the redesign vision judge.

## `model` (type: `string`):

Redesign judge model. Default cheap Haiku for verify; bump for prod. Swap provider to OpenAI for Concept3D's env per signals.json.

## Actor input object example

```json
{
  "domain": "gatech.edu",
  "signals": [
    "competitor_cms",
    "map_axe",
    "redesign"
  ],
  "model": "claude-haiku-4-5-20251001"
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("sculpted/concept3d-signals").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("sculpted/concept3d-signals").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 '{}' |
apify call sculpted/concept3d-signals --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/9HZCefpHyxr3UzS9s/builds/GMKOFzRLqztKiaE6W/openapi.json
