Tech & Trust Profile

Get tech & trust data for a specific run

Changed on

Get full tech & trust data for a specific historical monitoring run, including per-competitor security headers, trust signals, technology stack, robots.txt, and DNS infrastructure. Fields we could not measure are null, with a sibling availability object giving the reason; never read a null as zero, false or absent, and note that a measured 0 / false / empty list is reported as itself and is a real finding. A competitor whose robots.txt reads exists: false with NO availability marker genuinely publishes none, which allows all crawlers — a real finding, distinct from a null. A run that finished but produced no summary answers 404 run_not_summarized, which is a different fact from run_not_found: the run exists, it just has nothing to report. It used to answer 200 with an all-zero summary invented from the missing one.

get/v1/projects/{projectId}/tech-trust/history/{runId}

Request

  • Base URL: https://api.competlab.com
  • URL: https://api.competlab.com/v1/projects/{projectId}/tech-trust/history/{runId}
  • Auth: API key in header CL-API-Key

Path parameters

runIdstring required
Example:507f1f77bcf86cd799439012

Run ID

projectIdstring required
Example:507f1f77bcf86cd799439011

Project ID

Response

Example response

{
  "item": {
    "runId": "507f1f77bcf86cd799439011",
    "completedAt": "2026-03-15T10:00:00.000Z",
    "summary": {
      "competitorsChecked": 6,
      "competitorsSuccessful": 5,
      "customer": {
        "domain": "yoursite.com",
        "securityScore": 72,
        "securitySignalsAvailable": {
          "reason": "site_uses_behavioral_protection"
        },
        "trustSignalCount": 8,
        "techStackCount": 14,
        "techTrustAnalysisAvailable": {
          "reason": "tech_trust_fetch_failed"
        }
      },
      "topSecurityCompetitor": {
        "domain": "rival.com",
        "securityScore": 95
      },
      "topTrustCompetitor": {
        "domain": "other.com",
        "trustSignalCount": 15
      },
      "securityScoreGap": -23,
      "trustSignalGap": -7,
      "comparableCompetitors": 4
    },
    "competitors": [
      {
        "domain": "competitor.com",
        "securityHeaders": {
          "score": 85,
          "hsts": true,
          "csp": true,
          "xFrameOptions": true,
          "xContentTypeOptions": true,
          "signalsAvailable": {
            "reason": "site_uses_behavioral_protection"
          }
        },
        "trustSignals": {
          "totalCount": 10,
          "categories": {
            "compliance": 3,
            "reviews": 4,
            "socialProof": 2,
            "certifications": 1,
            "disclosures": 1
          }
        },
        "technologyStack": {
          "tech": [
            "React",
            "Next.js",
            "TypeScript"
          ],
          "growth": [
            "Google Analytics",
            "HubSpot"
          ],
          "engagement": [
            "Intercom",
            "Zendesk"
          ],
          "totalCount": 12,
          "partialDetection": {
            "reason": "site_uses_behavioral_protection"
          }
        },
        "robotsTxt": {
          "exists": true,
          "totalRules": 5,
          "robotsTxtAvailable": {
            "reason": "access_http_error_status"
          }
        },
        "aiAccess": {
          "measurement": {
            "status": "measured",
            "measuredAt": "2026-08-13T04:12:00.000Z",
            "couldNotMeasureReason": "access_http_error_status",
            "sourcesRead": {
              "robotsTxt": {
                "state": "read",
                "reason": "access_http_error_status",
                "httpStatusCode": 200
              },
              "pageMetaRobotsTag": {
                "state": "read",
                "reason": "access_http_error_status",
                "httpStatusCode": 200
              },
              "httpResponseHeaders": {
                "state": "read",
                "reason": "access_http_error_status",
                "httpStatusCode": 200
              }
            },
            "explanations": [
              {
                "code": "training_blocked",
                "text": "Blocking a training crawler asks these operators not to use your content for model training. It does not affect whether AI assistants can cite you."
              }
            ]
          },
          "assistantAccess": [
            {
              "assistantName": "ChatGPT",
              "crawlerAccessStatus": "can_reach_site",
              "appliesTo": "whole_site",
              "decidedByCrawlers": [
                {
                  "userAgentToken": "OAI-SearchBot",
                  "crawlerPurpose": "fetches_pages_to_cite_in_answers",
                  "honoursRobotsTxt": "yes",
                  "honoursRobotsTxtEvidence": "operator_documented",
                  "decidedByRuleFor": "wildcard_catch_all",
                  "decidedByDirective": "Disallow: /",
                  "decidedByLineNumber": 14
                }
              ],
              "explanations": [
                {
                  "code": "training_blocked",
                  "text": "Blocking a training crawler asks these operators not to use your content for model training. It does not affect whether AI assistants can cite you."
                }
              ]
            }
          ],
          "modelTrainingAccess": [
            {
              "modelOperatorName": "OpenAI",
              "trainingAccessStatus": "may_use_content_for_training",
              "decidedByCrawlers": [
                {
                  "userAgentToken": "OAI-SearchBot",
                  "crawlerPurpose": "fetches_pages_to_cite_in_answers",
                  "honoursRobotsTxt": "yes",
                  "honoursRobotsTxtEvidence": "operator_documented",
                  "decidedByRuleFor": "wildcard_catch_all",
                  "decidedByDirective": "Disallow: /",
                  "decidedByLineNumber": 14
                }
              ],
              "explanations": [
                {
                  "code": "training_blocked",
                  "text": "Blocking a training crawler asks these operators not to use your content for model training. It does not affect whether AI assistants can cite you."
                }
              ]
            }
          ],
          "rulesThatMayNotWork": [
            {
              "userAgentInFile": "ChatGPT-User",
              "directiveInFile": "Disallow: /",
              "whyItMayNotWork": "operator_exempts_user_initiated_requests",
              "explanation": {
                "code": "training_blocked",
                "text": "Blocking a training crawler asks these operators not to use your content for model training. It does not affect whether AI assistants can cite you."
              }
            }
          ],
          "rulesWithUnintendedScope": [
            {
              "userAgentInFile": "GPTBot",
              "kind": "escapes_restrictions_others_get",
              "affectedRules": [
                "Disallow: /use-cases/fintech",
                "Disallow: /events/*"
              ],
              "explanation": {
                "code": "training_blocked",
                "text": "Blocking a training crawler asks these operators not to use your content for model training. It does not affect whether AI assistants can cite you."
              }
            }
          ],
          "additionalObservations": [
            {
              "code": "training_blocked",
              "text": "Blocking a training crawler asks these operators not to use your content for model training. It does not affect whether AI assistants can cite you."
            }
          ],
          "crawlerCatalogVersion": "2026-08-13"
        },
        "dnsInfrastructure": {
          "emailProvider": "Google Workspace",
          "dnsProvider": "Cloudflare",
          "emailProviderAvailable": {
            "reason": "dns_lookup_failed"
          },
          "dnsProviderAvailable": {
            "reason": "dns_lookup_failed"
          }
        }
      }
    ]
  }
}

Changes

    • breaking

      the response property ////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property /////////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property //////////// became optional for the status

    • breaking

      the response property /////////////// became optional for the status

    • breaking

      the response property /////////////// became optional for the status

    • warning

      added the new not_found enum value to the / response property for the response status