{
  "openapi": "3.0.1",
  "info": {
    "title": "Actor A/B Tester — Compare Two Actors Side by Side",
    "description": "Run two Apify actors with identical input in parallel and compare results side by side. Measures result count, field coverage, execution speed, and compute cost. Declares a winner with percentage diffs. Returns JSON/CSV/Excel.",
    "version": "1.0",
    "x-build-id": "fd1ROFgZTpPMNhoaH"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/ryanclinton~actor-ab-tester/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-ryanclinton-actor-ab-tester",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/ryanclinton~actor-ab-tester/runs": {
      "post": {
        "operationId": "runs-sync-ryanclinton-actor-ab-tester",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/ryanclinton~actor-ab-tester/run-sync": {
      "post": {
        "operationId": "run-sync-ryanclinton-actor-ab-tester",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "actorA",
          "actorB",
          "testInput"
        ],
        "properties": {
          "actorA": {
            "title": "Actor A",
            "type": "string",
            "description": "Actor ID or name for the first actor to test (e.g. 'apify/web-scraper' or the opaque actor ID)",
            "default": "apify/web-scraper"
          },
          "actorB": {
            "title": "Actor B",
            "type": "string",
            "description": "Actor ID or name for the second actor to test (e.g. 'apify/cheerio-scraper' or the opaque actor ID)",
            "default": "apify/cheerio-scraper"
          },
          "testInput": {
            "title": "Test Input",
            "type": "object",
            "description": "JSON input passed identically to both actors. Must be compatible with both actors' input schemas.",
            "default": {
              "startUrls": [
                {
                  "url": "https://example.com"
                }
              ]
            }
          },
          "mode": {
            "title": "Test mode",
            "enum": [
              "smoke",
              "standard",
              "decision",
              "high_stakes"
            ],
            "type": "string",
            "description": "Preset that maps to a runs-per-actor count and a readiness ceiling. 'smoke' (1 run) is capped at 'monitor' readiness and can never return 'actionable'. 'standard' (3) is the sensible default for routine comparison. 'decision' (5) is suitable for production switching. 'high_stakes' (10) is for decisions where the verdict needs to survive scrutiny.",
            "default": "standard"
          },
          "decisionProfile": {
            "title": "Decision profile",
            "enum": [
              "balanced",
              "speed_first",
              "cost_first",
              "output_first",
              "reliability_first"
            ],
            "type": "string",
            "description": "How the winner is weighted. 'balanced' spreads weight across all metrics. 'speed_first' / 'cost_first' / 'output_first' / 'reliability_first' upweight one dimension. The chosen profile is reported alongside the verdict so the result stays auditable.",
            "default": "balanced"
          },
          "runs": {
            "title": "Runs per actor (override)",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Override the runs count set by the mode preset. If set, this wins over mode. Range 1–10. More runs = less noise, N× the Apify platform bill."
          },
          "includeStoreContext": {
            "title": "Include Store popularity context",
            "type": "boolean",
            "description": "Fetch each actor's Apify Store stats (monthly users, star rating, categories) and attach to the result as informational context. Store signals NEVER affect the winner score — they are reported separately so reviewers can weigh trust context without contaminating the comparator.",
            "default": true
          },
          "compareToLastComparableRun": {
            "title": "Compare to last comparable run",
            "type": "boolean",
            "description": "Look up the previous run for the same pair + same testInput + same mode + same profile, and report delta (winner change, confidence delta, metric drift). First run of a pair emits 'found: false' — not a failure.",
            "default": false
          },
          "timeout": {
            "title": "Timeout per run (seconds)",
            "minimum": 10,
            "maximum": 3600,
            "type": "integer",
            "description": "Maximum time in seconds to wait for each child actor run to complete. Both actors run their N runs in parallel.",
            "default": 300
          },
          "memory": {
            "title": "Memory per run (MB)",
            "minimum": 128,
            "maximum": 32768,
            "type": "integer",
            "description": "Memory allocation in megabytes for each child run. Higher memory = faster execution but higher sub-actor cost.",
            "default": 512
          },
          "apiToken": {
            "title": "Apify API Token (optional)",
            "type": "string",
            "description": "Your Apify API token, used to start and poll the two child actors. Leave blank when running on your own account — the actor falls back to the built-in APIFY_TOKEN. Required when the tester needs to start third-party actors outside the runner's scope. Find it at https://console.apify.com/settings/integrations"
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}