Skip to main content

Build a connector

A connector indexes content from a source Gety doesn't cover by default. This guide takes you from the sample project to a connector installed in Gety. For the full field and API reference, see Connector reference.

Know the current scope

A connector is a Deno and TypeScript program that polls a source and yields documents for Gety to index.

It can:

  • Pull data from a stable source it can access, such as a web API, local enumeration, or internal service
  • Index text content with stable IDs, titles, and metadata
  • Use persisted state to track incremental progress and add, update, or delete documents

It can't:

  • Add its own UI to Gety beyond manifest-declared configuration fields
  • Fetch, extract, or cache remote files on demand when a user opens a result
  • Use a per-document dynamic link rule; document links are declared once in the manifest

If the source only exposes files that Gety would need to fetch and extract later, put the text your connector already has into content and store a stable URL or file path in metadata.

For example, Notion is a good connector fit: use the Notion API as the stable source, convert Notion blocks to Markdown with a library such as souvikinator/notion-to-md, then send that Markdown as the indexed content in Gety.

A media player is usually not a good connector fit. It is mainly an interactive UI, not a stable text source. Connectors also work poorly for sources that don't expose a reliable API, stable local files, or durable IDs for incremental sync.

Prerequisites

Before you start, install:

  • Git to clone the sample connector.
  • Deno to build, test, and run the connector.

Create a connector with an AI agent

If your AI coding tool supports Skills, use Gety's connector skill first. It gives the agent the connector contract, sample project workflow, and verification steps.

npx skills add gety-ai/gety-skills --skills create-gety-connector

Then tell the agent what you want to index:

Use the create-gety-connector skill to create a Gety connector for [source].

Ask me for any missing details before you start coding.

If your AI coding tool doesn't support Skills, paste this into the chat instead:

Create a Gety connector for [source]. Use https://docs.gety.ai/build-a-connector.md as the implementation workflow and https://docs.gety.ai/connector-reference.md as the full connector contract and field reference. Before writing code, ask me to clarify any missing details.

Don't paste API keys or other secrets into a chat. Put secrets in connector configuration fields or local .env files.

If you're building by hand, follow the steps below.

Start from the sample

Clone the sample connector. Don't build the skeleton from scratch; the sample includes the build script, generated config types, local runner, and verification tasks.

git clone https://github.com/gety-ai/gety-sample-connector my-connector
cd my-connector

Review the project structure

manifest.json          # Connector metadata and configuration schema
src/index.ts # Connector implementation
src/index.test.ts # Unit tests
src/gen/manifest.d.ts # Generated config type; do not edit
dist/main.js # Built entry loaded by Gety
deno.json # Tasks: build, check, test, verify, runner
dev/runner.ts # Local lifecycle runner
scripts/build.ts # esbuild bundler

dist/main.js is the entry Gety loads. After editing src/index.ts, run deno task build; changing the source file alone doesn't update the built connector.

Plan the document contract first

Before writing code, decide how the source maps to Gety documents. Settle these up front:

  • The source and its authentication method.
  • A stable document ID that survives across polls.
  • How each record maps to title, content, and metadata.
  • How deleted or archived records are detected and removed.
  • What link opens when a user selects a search result.

Write a minimal manifest

manifest.json tells Gety how to install and run the connector:

{
"id": "my_connector",
"name": "My Connector",
"version": "0.1.0",
"min_gety_app_version": "0.5.1",
"capabilities": ["data-source"],
"entry": "dist/main.js",
"description": "Indexes documents from My Connector.",
"schedule": { "strategy": "interval", "interval_seconds": 3600 },
"doc_link": { "kind": "url", "field": "url" },
"config": {
"fields": [
{
"id": "api_key",
"title": "API Key",
"type": "password",
"required": true,
"description": "Create this token in the service settings."
}
]
}
}

See Connector reference for every manifest field.

Implement src/index.ts

Your connector is a class that extends Connector<Config, State>. Implement poll() as an async generator that yields batches of document updates and a state checkpoint.

import { Connector, type PollResult, del, upsert } from '@gety-ai/connector-sdk';
import type { ManifestConfig } from './gen/manifest.d.ts';

type State = {
cursor?: string;
};

export default class MyConnector extends Connector<ManifestConfig, State> {
async *poll(): AsyncGenerator<PollResult, void, unknown> {
let cursor = this.lastState?.cursor;

for await (const page of fetchPages(this.config.api_key, cursor, this.signal)) {
yield {
updates: [
...page.items.map((item) =>
upsert({
id: item.id,
title: item.title,
content: item.body,
content_format: 'markdown',
doc_type: 'my:item',
doc_updated_at: item.updatedAt,
metadata: { url: item.url },
}),
),
...page.removed.map((id) => del(id)),
],
state: { cursor: page.next_cursor },
};
cursor = page.next_cursor;
}
}
}

Key points:

  • upsert(doc) adds or updates a document. Only id and title are required; id must stay stable across polls.
  • del(id) removes a document when the source proves it's gone.
  • this.config contains the values from your manifest configuration fields.
  • this.lastState contains the state from the last successful poll progress.
  • this.signal aborts when the user disables or restarts the connector. Pass it to fetches when possible.

Manage state and batches

Yield a state checkpoint with each batch, after the updates it covers. Gety persists that state as lastState for the next poll, so a failed poll can retry from the last committed checkpoint.

Don't advance state before yielding the documents it covers. Yield at a boundary the source can retry safely, such as an API page or a durable cursor.

Avoid these patterns

These mistakes can cause memory pressure or broken links:

  • Loading all remote data into memory at once. Prefer paging or streaming the source instead.
  • Using temporary URLs in doc_link. Links must stay stable after the poll ends.
  • Putting large blobs in metadata. Keep metadata small and index text through content.
  • Reading this.config in the constructor. Configuration is available in lifecycle methods such as onLoad() and poll(), after Gety injects it.

Verify locally

Run the sample verification task before installing the connector:

deno task verify

verify runs formatting, lint fixes, config type generation, type-checking, tests, and the build. Then exercise the connector lifecycle with the local runner:

cp .env.example .env
deno task runner -- --reset-state

The runner calls onLoad() and poll() and writes each run's output under dev/runs/<timestamp>/: documents, updates, deletes, and state snapshots. Check for stable IDs, expected content, correct metadata, and RFC 3339 timestamps. --reset-state ignores the saved runner state so you can test a clean first poll.

If your .env needs secrets such as an API key, edit the file yourself. Don't paste secrets into a chat with an agent.

Install in Gety

  1. Run deno task build to refresh dist/main.js.
  2. Open Gety → Settings → Connectors and install your connector folder.
  3. Fill in any required configuration fields in the install dialog.
  4. Confirm the install.
  5. Let Gety run the connector according to its update strategy. For a manual connector, click Update now.

After later code edits, run deno task build again and click Restart in Gety to load the new build.

Next steps

For the complete contract, including manifest fields, configuration field types, the SDK lifecycle, and WireDoc fields, see Connector reference.