Sales teams keep track of the people and companies they sell to in a CRM, which is a database built for customer records. Apollo.io is one of these tools. It also runs sequences, which are scheduled series of outreach messages sent to a contact.
An AI model can't answer questions about any of that on its own, because every conversation with it starts from zero. cognee is an open source project that gives AI agents a memory. You feed it your data, it builds a knowledge graph (a map of the things in your data and how they connect), and an agent can search that map later.
A connector is the piece of code that moves data from a tool like Apollo into cognee. I built the Apollo connector for Mergetober, a month of open source work on cognee integrations, and it was merged on October 19.
What the connector does
Once your Apollo data is in cognee, you can ask something like "Which contacts at Acme are in an active sequence?" and get an answer based on your own records.
Copying the data once would be simple. The harder part is that a CRM changes every day, so the connector has to handle two things on every later run:
- Only process records that changed. Without this, each run would send your whole CRM through the AI processing step again.
- Remove records you deleted in Apollo. If you delete a contact, your agent shouldn't keep answering questions about them.
Apollo makes both of these harder than you'd expect, and most of this post is about why.
Trying it
You'll need an Apollo API key, which means a paid plan or a trial, because free plans don't have API access to contact and account search. You'll also need an API key for an AI model provider, since cognee uses one to build the graph.
The connector is in the cognee-community repo, and you run it from there with uv:
git clone https://github.com/topoteretes/cognee-community.git
cd cognee-community/packages/connector/apollo
uv sync
export APOLLO_API_KEY="your-apollo-key"
Put your model key in a .env file as LLM_API_KEY, then run the example:
uv run python examples/example.py
The part of the example that does the work looks like this:
source = apollo_source(api_key=api_key, resource_name="apollo_crm_main")
await cognee.remember(
source,
dataset_name="apollo_crm",
primary_key="id",
write_disposition="merge",
max_rows_per_table=0,
)
dataset_name is the place in cognee where this data lives. resource_name is a name you pick for this Apollo account, and it has to stay the same between runs. write_disposition="merge" tells cognee to update existing records. Leave it out and the second sync wipes the first one.
The connector reads your contacts, your company accounts and your sequences. It leaves emails, phone numbers and social profiles out on purpose, and it doesn't use any of the Apollo endpoints that cost credits.
Problem 1: Apollo doesn't tell you what changed
Many services stamp each record with the time it was last updated, so a connector can ask for everything newer than its last run. Apollo has an updated_at field, but it doesn't work for this. I enrolled a contact in a sequence on a live account and the contact's timestamp stayed the same, even though that's the kind of change you'd want your agent to know about. Company records don't come back with the timestamp at all.
So the connector reads every record on each run and turns it into text. It then computes a fingerprint of that text, a short code that changes whenever the text changes. It saves the fingerprints, and on the next run any record with the same fingerprint as before is skipped.
The downside is that reading everything uses up requests, and Apollo limits how many you can make per minute, per hour and per day. The connector stops before it hits a limit, saves its place, and picks up from there on the next run. A large account on a small plan will take several runs to get through.
Problem 2: Apollo doesn't tell you what was deleted
Apollo has no list of deleted records. All the connector can see is that a record it knew about isn't in the list anymore, and that doesn't prove it was deleted. The run might have stopped early, or the list might have been cut off, because Apollo search stops at 50,000 records.
So the connector only acts on a list it read all the way to the end. For each record missing from that list, it asks Apollo about that one record directly. It forgets the record only if Apollo says it's gone, or if the record no longer matches the filters you chose.
What the code review found
Before the connector was merged, goran-radonic, a cognee maintainer, reviewed it over two rounds and left 31 inline comments. Two of the problems they found show how easily the delete logic could go wrong.
The first was about two Apollo accounts sharing one dataset. Both used the same default name, so in the reviewer's test, syncing the second account removed the first account's contacts, and the next sync of the first account removed the second's. The name is now required, and a run refuses to continue from saved progress that belongs to a different Apollo team.
The second was in how I recognized a deleted record. Apollo reports one with an error message, and my check was too loose: a different error, such as "This contact does not exist in the stage you filtered", would also have counted as deleted. The check now accepts only the exact messages Apollo uses for deleted records, plus a plain 404.
Did it work?
I tested it on a real Apollo trial account with records I made for the purpose: two companies, four contacts and one sequence.
| What I did | What happened |
|---|---|
| First sync | 7 documents stored |
| Synced again with no changes | all 7 skipped |
| Edited one contact's job title | 6 skipped, 1 updated |
| Deleted a contact and a company in Apollo | both removed, nothing else touched |
That test covered getting data in and taking it out, and it ran on the version I first submitted. After the review changes I checked the fixes with the automated tests, which run against a fake version of Apollo, and with a few specific calls to the real API. The merged version has 83 tests.
Limits
- Accounts over 50,000 records need stage or list filters, otherwise deleted records aren't detected.
- Each contact keeps its latest 50 activity events.
- Apollo plans to remove the error fields the delete check reads on 16 February 2027, and it hasn't documented a replacement yet, so that check will need updating before then.
- The dataset contains names, job titles and companies, so share it only with people who are allowed to see your CRM.
The code and setup details are in the Apollo connector folder.
Top comments (0)