Short answer: install cognee-community-connector-canny, set CANNY_API_KEY and LLM_API_KEY, and pass canny_source() to cognee.remember(). Leave write_disposition alone: this connector needs Cognee's default, replace. Your Canny posts, with their vote counts, statuses and comments, become a knowledge graph in Cognee, so you can ask it what your users want most and why.
A product team's question is simple: what do users want most, and why? In Canny the vote count answers the first half. The second half, the why, is spread across the comments of many posts, and you only see it by opening them one at a time. I wanted to ask both halves at once, so I built a Canny connector for Mergetober, the open source month run by WeMakeDevs and Cognee.
Cognee (docs) is an open source memory layer for AI agents. You give it data with add, cognify turns that data into a knowledge graph (this step needs an LLM API key), and search asks the graph questions. A connector is a way to feed it a tool's data instead of a folder of files.
What does the Canny connector for Cognee do?
- Turns every post into one document: title, details, board, category, status, vote score, comment count, author, tags, creation time and comments, oldest first. The vote score is part of the text, so the graph can weigh demand.
- Lets you narrow the sync with
board_ids,statusesorinclude_comments=False. - Leaves out admin-only internal comments unless you pass
include_internal=True. - Re-reads your boards on every run, but only reprocesses posts that changed.
- Forgets posts you delete or merge in Canny.
How do you connect Canny to Cognee?
Setup takes four steps:
- Install the package. It pins
cognee==1.4.0. - In your Canny company settings, open the API section and copy your secret API key.
- Export
CANNY_API_KEY(or passapi_key=) andLLM_API_KEY. Cognee needs the LLM key for entity extraction. - Sync and search.
uv pip install cognee-community-connector-canny export CANNY_API_KEY="..." export LLM_API_KEY="sk-..." import cognee from cognee_community_connector_canny import canny_source await cognee.remember( canny_source(), # or canny_source(board_ids=[...], statuses=[...]) dataset_name="canny", ) answer = await cognee.search( query_text="Which feature requests have the most votes, and why do users want them?", query_type=cognee.SearchType.GRAPH_COMPLETION, datasets=["canny"], ) Treat the key as a secret. Canny's API takes it as an apiKey field in the request body, so keep it out of code you commit.
What can you ask once your feedback board is in memory?
After a sync, cognee.search answers questions against the graph. The query in the connector's example is "Which feature requests have the most votes, and why do users want them?" Because every document carries its status, you can also sync only some posts with statuses=[...] (planned, say, or in progress) and ask about just those.
Why is the Canny sync a snapshot?
Canny's posts/list endpoint has no "updated after" filter, and Canny has no feed of deleted posts. So there is nothing to ask for "what changed since last time". Every run reads the whole board, 100 posts per request plus one more request for the comments of each post that has any, and the connector works out the rest.
Unchanged posts keep the same id and the same content, so Cognee gives them the same content hash and doesn't process them again. Only new posts, new comments, vote or status changes and edited text go through cognify. So "incremental" here means incremental processing, not incremental API calls. The API calls are the cheap part. The LLM calls inside cognify are usually the bigger bill, and those are the ones this saves.
Two things follow. First, a post that gets one new vote is processed again, because the score is part of its text. I think that's the right trade for a connector whose whole point is weighing demand. Second, this is the one connector of mine where you must not use write_disposition="merge", which my Zoho CRM and Freshsales connectors require because those APIs can say what changed. A snapshot finds deletions by absence. With replace, each run rewrites the staging table with the posts that exist right now, and anything missing is cleaned out of the graph. With merge or append a deleted post just stays, and forget-on-delete breaks.
What happens when a post is deleted or merged in Canny?
A post you delete, merge into another post or move out of the scope you chose (a board you filtered out, say) isn't in the next snapshot. Cognee's orphan_cleanup then removes it from the graph and the vector store. Any error aborts the run, so a partial read can never look like a mass deletion.
What surprised me while building it?
Skip paging can make a live post look deleted
Canny's posts/list pages with skip, so page two means "whatever is left after the first N posts". If someone deletes a post while the sync is running, every post after it moves up one place. The next page then starts one post too late and skips a post that still exists. In a snapshot sync, a post you never read looks exactly like a post that was deleted, so Cognee would forget a post that's still live.
The fix is plain. Consecutive pages overlap by 10 posts and duplicates are dropped by id. Paging also stops when a page returns no new posts. I haven't seen this happen on a live board. It follows from how skip works, and each paging fix has a test that fails if you remove it.
A fresh install pulled a newer Cognee than I had tested
With cognee>=1.4.0, a fresh install pulled cognee 1.6.3. The connector now pins cognee==1.4.0, like the other connectors in the repo. The catch for you is that installing it pins Cognee to 1.4.0 in that environment, so use a virtual environment of its own if you run a newer Cognee elsewhere.
How did I test it without a live Canny account?
I haven't run this connector against a live Canny account yet, and I'd rather say so than leave you to find out. What I have is 22 tests that run against a fake HTTP client and a temporary SQLite database, so they need no API key and no network. Run them with uv run pytest tests/ from packages/connector/canny. ruff check and ruff format --check are clean.
Frequently asked questions
How many Canny API requests does one sync use?
Posts are read 100 per request, and each post with comments needs one more request. As an example, a board with 300 posts where 200 have comments costs 3 + 200 = 203 requests per sync, because every run reads the whole board.
Canny's API reference sets limits per API key: Free allows 5 requests per second, 100 per minute and 1,000 per hour. Pro allows 10, 300 and 5,000, and Business allows 20, 600 and 15,000. On the Free plan that example board takes about two minutes. The connector retries 429 responses and honors Retry-After, but a board that needs more than 1,000 requests per sync can't finish inside an hour on Free.
Which boards and statuses does it sync?
All boards and all statuses by default. Pass board_ids=[...] to limit it to some boards and statuses=[...] to limit it to some statuses. Pass include_comments=False to skip comments.
Does it ingest internal comments?
No. Admin-only internal comments are skipped unless you pass include_internal=True. Leave that off if other people will search the graph.
Try it
The code is in cognee-community pull request #218, open for review, and it closes cognee issue #4757. I also built connectors for Readwise, Help Scout, Zoho CRM and Freshsales, and each gets its own post.
If you run it against your own Canny board, tell me what you ask it and where it breaks.

