Userlens Documentation Audit
Userlens publishes a polished marketing site and a working SDK, but the developer documentation surface is fractured across four domains (userlens.io, gitbook, GitHub, PyPI), contradicts itself on compliance, and is shipped under a different company's brand name. For a Y Combinator-backed B2B SaaS platform that asks customers to pipe production analytics data through it, the doc plumbing is well below the bar.
1. The only "SDK Documentation" entry point lives off-domain under a different brand (significant)
Location: Homepage footer and /pricing footer (labels: "SDK Documentation" / "SDK Docs"), resolving to userlens.gitbook.io/userlens-analytics/
Problem: The homepage advertises a "SDK Documentation" link and /pricing repeats it as "SDK Docs". The link resolves off-domain to a GitBook (userlens.gitbook.io/userlens-analytics/). There is no docs.userlens.io (ECONNREFUSED) and no userlens.io/docs (404). The GitBook subdomain is never named anywhere in the userlens.io copy. The SDK itself is in github.com/wudpecker/userlens-analytics-sdk — a third brand. So the docs trail bounces from userlens.io → userlens.gitbook.io → github.com/wudpecker with no cross-references explaining the relationship.
Consequence: A developer or security reviewer evaluating Userlens lands on a GitBook under a third-party host, with no userlens.io-branded confirmation that they're in the right place. Security-conscious teams stop here. Agents (Claude, Cursor) crawling userlens.io see no API/SDK content because none of it is on the canonical domain.
The fix: Either host the docs at docs.userlens.io (CNAMEing the GitBook works) or relabel the footer link "SDK Documentation (GitBook)" and add a one-paragraph "Where our docs live" callout on userlens.io explaining the GitBook + GitHub split.
2. SDK is published under the "wudpecker" brand, not "Userlens" (critical)
Location: github.com/wudpecker/userlens-analytics-sdk, pypi.org/project/userlens-analytics-sdk/ (Author: "Wudpecker", maintainer: ankurwudpecker), userlens.gitbook.io/userlens-analytics/
Problem: The official npm/JS SDK README lives in the wudpecker GitHub organization, the Python SDK on PyPI lists "Wudpecker" as the Author, and the parent org's tagline reads "storing meeting knowledge" — a different product entirely. Nothing on userlens.io explains that wudpecker is the legal predecessor or sibling brand. The PyPI page literally says "The author of this package has not provided a project description."
Consequence: A developer installing userlens-analytics-sdk via pip or npm has no way to confirm they're pulling the official package versus a typo-squat or abandoned fork. Security-conscious engineering teams will block the install. Agents searching GitHub for "Userlens SDK" by org name will find nothing.
The fix: Either migrate the repos to a userlens GitHub org (with redirects), or add a clear README banner in every wudpecker repo explaining the brand relationship. Fill in the PyPI project description with a one-paragraph "This is the official Userlens Python SDK" plus a link to the GitBook.
3. SOC 2 / GDPR claims contradict each other across three pages (critical)
Location: Homepage, /llms.txt, /privacy-security
Problem: Three different stories about the same compliance posture:
- Homepage: "SOC 2 Type 2 (in progress) and GDPR compliance"
/llms.txt: "The company maintains SOC 2 Type 2 certification and GDPR compliance"/privacy-security: lists encryption, IAM, backups — but is entirely silent on SOC 2, ISO 27001, or any third-party certification.
So the homepage says SOC 2 is in progress, the AI-facing summary says it's already maintained as a certification, and the actual security page never mentions it.
Consequence: This is a procurement blocker. Any enterprise buyer's security review will fail this comparison immediately, and Userlens explicitly markets to enterprise ("OKTA and SSO access", "complex requirements"). Agents pulling llms.txt will confidently tell users Userlens is SOC 2 certified — which the homepage contradicts.
The fix: Pick one true status and propagate it. If SOC 2 Type 2 is in progress, say "Type 2 audit in progress, targeting [quarter]" on all three surfaces, and remove the "maintains SOC 2 Type 2 certification" claim from llms.txt until the audit completes.
4. llms-full.txt returns 404 despite the AI-friendly stance (significant)
Location: /llms-full.txt (404), /robots.txt (declares Content-Signal: ai-train=yes, search=yes, ai-input=yes and explicit Allow for ChatGPT, Claude, Perplexity, Google-Extended, etc.)
Problem: Userlens has an llms.txt file (a 9-line marketing summary) and a robots.txt that aggressively opts into every AI crawler, but no llms-full.txt. There is no concatenated machine-readable corpus that a coding agent can ingest.
Consequence: The llms.txt alone tells an agent positioning and customer logos but nothing about how to integrate. An agent asked "how do I install the Userlens SDK" against llms.txt gets zero usable code. The site signals "please train on me" but doesn't expose the content in a form agents can use efficiently.
The fix: Generate an llms-full.txt that concatenates: the SDK quickstart, pushEvent API, the React/Next.js setup, the HTTP API reference, the PostHog/Segment integration steps, and the auth/WRITE_CODE flow. Even a 50KB file would 10x agent utility here.
5. No HTTP API reference is reachable from userlens.io (critical)
Location: Entire userlens.io sitemap (88 URLs), /pricing ("SDK Docs" link)
Problem: The sitemap.xml enumerates the entire public surface — homepage, pricing, privacy-security, customer-stories, blog, agent, privacy-policy, terms-of-service — and contains zero API reference, SDK pages, or integration docs. The GitBook references an "HTTP API — Direct integration for any language or environment", and the GitHub README links to docs/api-reference.md, but neither is accessible by browsing userlens.io. Even the existence of an HTTP API is invisible to anyone who doesn't first find the GitHub org.
Consequence: Developers evaluating whether to integrate cannot answer basic questions — what's the base URL, what's the auth header, what payload schema does /track expect, what are the rate limits — without first reverse-engineering it from the GitHub repo.
The fix: Publish the HTTP API reference at userlens.io/docs/api (or surface it via the GitBook with a clear nav entry). Include base URL, auth header format, every endpoint with request/response schemas, rate limits, and error codes. Bonus: ship an OpenAPI spec so agents can programmatically discover endpoints.
6. The WRITE_CODE config value is undocumented and unexplained (significant)
Location: github.com/wudpecker/userlens-analytics-sdk README quickstart
Problem: The React quickstart shows:
WRITE_CODE: 'your-write-code', // From app.userlens.io/settings/integrations/userlens-sdk
Nowhere in the scraped content is WRITE_CODE defined. Is it a write key? An API token? A site ID? What's the format? Is it secret (must live in env vars / a backend proxy) or is it public (safe to ship in a client bundle)? How is it rotated? The placeholder 'your-write-code' is also not marked as a placeholder in any structured way an agent could detect.
Consequence: A developer copy-pasting this snippet into a React app has no signal as to whether they've just embedded a sensitive credential in their client bundle. An AI agent extracting this example will run it verbatim with the literal string 'your-write-code' and silently fail.
The fix: Define WRITE_CODE in a Concepts page: what it is, whether it's public or secret, how to rotate it, and which deployment model (client-side vs. proxy) it's safe in. In examples, use a clearly fake <YOUR_WRITE_CODE> placeholder or process.env.USERLENS_WRITE_CODE so agents and humans alike know to substitute.
7. Compliance / data residency disagreement between Privacy Policy and Terms (significant)
Location: /privacy-policy, /terms-of-service, /privacy-security
Problem: The Privacy Policy says personal data resides "on AWS servers, specifically in the EU (Frankfurt) eu-central-1 and EU (Stockholm) eu-north-1 regions." Customer stories and the YC page describe customers like Quartr, Vainu, Luminovo, and US-based prospects. Nowhere is there a data-residency selector, US-region option, or "data is processed in the EU only" call-out on the security page. The /privacy-security page also doesn't mention region at all, while the /privacy-policy page does.
Consequence: US-based enterprise buyers will assume US data residency; EU buyers will want a binding statement on the security page, not buried in the privacy policy. A developer/security reviewer comparing the two pages will flag this as inconsistent.
The fix: Add a "Data Residency" section to /privacy-security that states "All customer data is processed and stored in AWS eu-central-1 and eu-north-1" (or whatever the real answer is), and cross-link from the privacy policy. If a US region exists or is planned, say so.
8. Retention timeframes contradict between Privacy Policy and Terms (significant)
Location: /privacy-policy vs. /terms-of-service
Problem: The Privacy Policy says retention is "only as long as necessary to serve the identified purposes... No specific retention timeframes are detailed." The Terms of Service give a concrete window: "rolling year and two previous calendar years. For longer data retention, fees apply upon negotiation."
Consequence: A buyer's legal team comparing the two will flag the inconsistency. Customers planning long-term historical analysis (the TrueClicks case study brags about "12 months of historical data maintained" and Luminovo about "2 years") have no clear, single source of truth for how long their data actually lives.
The fix: Add the concrete "rolling year + two previous calendar years" language to the Privacy Policy, and link from there to the Terms section for the negotiation clause. Better still, surface this on /pricing as a feature ("3 years of historical data included").
9. Marketing claims unsupported by accessible docs — "no new instrumentation" (significant)
Location: Homepage ("without requiring new instrumentation"), YC page, TrueClicks story ("50,000,000+ historical events migrated in one day")
Problem: The homepage claims integration "without requiring new instrumentation" for Mixpanel, Amplitude, PostHog, Salesforce, HubSpot, and Snowflake. But the only integration docs that exist (in the off-domain wudpecker/userlens-integration-docs GitHub repo) cover PostHog and Segment with screenshot-driven, manual steps. Salesforce, Snowflake, Amplitude, Mixpanel, HubSpot, Intercom, Pylon, Attio, and Stripe — all explicitly named on the homepage, pricing, or YC page — have no integration guides in the scraped content.
Consequence: A developer who picks Userlens specifically because they're on Amplitude or Snowflake has no public docs to validate the integration works the way they need. Procurement teams cannot do technical due diligence without booking a sales call.
The fix: Publish one integration guide per named source (even a stub explaining data mapping, auth flow, sync frequency). At minimum, list which integrations are "pull existing data" vs. which require instrumentation.
10. Python SDK is published, undocumented, and apparently unmaintained (significant)
Location: pypi.org/project/userlens-analytics-sdk/
Problem: The Python SDK on PyPI has:
- "The author of this package has not provided a project description"
- No code examples or method documentation
- Three releases all on the same day (Feb 19, 2025)
- A 1.5KB source tarball
- No GitHub link visible from the scrape
The GitHub README only documents the JS/React/Next.js SDK. The GitBook only documents JS. So a Python developer who finds the package on PyPI has zero documented way to use it.
Consequence: A Python backend developer either gives up or pip-installs an unmaintained, undescribed package and reverse-engineers it. Either outcome is bad. This also undermines the homepage's "Snowflake" integration claim, since Python is the natural language for that kind of pipeline.
The fix: Either deprecate and unpublish the PyPI package with a note pointing at the HTTP API and the Python backend-proxy guide, or invest in maintaining it: fill in the PyPI description, link to a userlens-analytics-python GitHub repo, and ship usage examples in the GitBook.
11. The "API Versioning Strategies" blog post says nothing about Userlens's own API versioning (minor)
Location: /blog/api-versioning-strategies-for-b2b-saas
Problem: Userlens publishes a thought-leadership blog post recommending API versioning strategies for B2B SaaS — but the post explicitly "does not reference any Userlens-specific API versioning implementation." Combined with finding #5 (no API reference exists), Userlens is publishing prescriptive advice for a versioning surface it doesn't expose publicly.
Consequence: Credibility hit for any developer who reads the post and then tries to find Userlens's own /v1/ namespace. The post reads as generic SEO content rather than a window into how Userlens itself operates.
The fix: Either add a "How Userlens does this" section to the post (with the actual API base URL and version scheme), or move it out of a developer-adjacent context.
12. Undocumented "Agents" referenced in customer stories with no product docs (minor)
Location: /customer-stories/homie
Problem: The Homie case study names specific products — "Onboarding Monitor, Health Score Agent, Meeting Prep Agent, Discover Upsell Agent" and "Activity Dots (daily, weekly, monthly, quarterly tracking)" — that appear nowhere on /agent, the homepage, the pricing page, or any docs surface. The /agent page lists generic capabilities but doesn't name these agents or explain what's included in which plan.
Consequence: A prospective buyer reading the case study can't tell whether "Meeting Prep Agent" is a separate SKU, a feature of Userlens Agent, or something custom-built for Homie. Sales conversations get awkward.
The fix: Add an "Agents" section to /agent (or a /agents index page) listing each named agent with a one-line description and which plan includes it.
13. PostHog integration guide ends with a broken word in a critical step (minor)
Location: github.com/wudpecker/userlens-integration-docs/blob/main/posthog_integration_documentation.md
Problem: The final line of the PostHog integration guide reads: "Now you can return to Userlens app to verifyent the integrations." verifyent is not a word — apparently a merge artifact of "verify" and something else.
Consequence: This is one of only two published integration guides for a platform whose homepage promises six-plus named integrations. A typo in the procedural last step undermines confidence that the rest of the steps were proofed. Agents transcribing the guide will faithfully reproduce the broken word.
The fix: Replace with a real verb (likely "verify") and audit the rest of the file for similar artifacts.
14. Smartly.io appears in llms.txt as a notable customer but has no case study (minor)
Location: /llms.txt vs. /sitemap.xml (/customer-stories/*)
Problem: llms.txt lists "Quartr, AhaSlides, TrueClicks, Vainu, Luminovo, Smartly.io, and Homie" as notable customers. The sitemap shows six published customer stories — every one of those names has a /customer-stories/<name> page except Smartly.io.
Consequence: An agent answering "do you have a Smartly.io case study?" gets told yes by llms.txt and finds nothing. Buyers checking references hit the same dead end. It also raises the obvious question for any human reader: is Smartly.io a real customer, an aspirational logo, or a churned account?
The fix: Either publish the Smartly.io story or remove Smartly.io from the customer roll-call in llms.txt. Keep the two surfaces in sync.
15. Older blog posts are unreachable from the blog index (minor)
Location: /blog index vs. /blog/customer-health-scoring-common-problems-and-fixes (Apr 2025)
Problem: The customer-health-scoring post is dated April 1, 2025 and reachable by direct URL, but does not appear in the visible blog index, which jumps from April 2026 entries straight back to late 2025. A "Load More" affordance is mentioned but the older post does not surface through the listed posts.
Consequence: A developer or buyer using the blog as the discovery surface will never find the older post unless they have the URL. Posts are reachable only via Google or by URL guessing — a discoverability hole that compounds with the sitemap's 88-URL listing being the only way to see what exists.
The fix: Paginate the blog index properly so all 80+ posts are reachable by clicking, or add an archive page grouped by month/year.
16. GitHub README documentation links use absolute paths that break outside github.com (minor)
Location: github.com/wudpecker/userlens-analytics-sdk README
Problem: Every documentation link in the README is written as /wudpecker/userlens-analytics-sdk/blob/main/docs/... — an absolute path starting with /. On github.com these resolve to https://github.com/wudpecker/... correctly, but the same README is shipped via npm, where the package page renders the README with those links broken (they resolve to https://www.npmjs.com/wudpecker/...).
Consequence: Developers who land on the npm page (a very common entry point) click "API Reference" or "Troubleshooting" and hit npm 404s. The audit already calls out the wudpecker/userlens brand split; this compounds it by making cross-domain navigation fragile.
The fix: Use fully-qualified https://github.com/wudpecker/userlens-analytics-sdk/blob/main/docs/... URLs in the README. They work everywhere and survive npm/GitHub mirrors.
17. Cross-doc voice and accuracy: Segment integration doc has a different product description and a grammar break (minor)
Location: github.com/wudpecker/userlens-integration-docs/blob/main/segment-integrations-docs.md
Problem: The Segment integration doc opens by describing Userlens as "your AI CSM twin that spot churn risks, and preps your client meetings & QBRs." The homepage describes the product as "AI agents that predict churn months before it happens." The Segment doc also contains a subject-verb agreement error ("twin that spot").
Consequence: Two of the only places a developer encounters a Userlens product description give different pitches in different voices, one ungrammatical. Agents summarizing "what is Userlens?" will get different answers depending on which doc they index. For an "AI CSM" product, sloppy copy on the integration page is a brand signal.
The fix: Adopt one canonical one-liner across llms.txt, the homepage, the GitBook intro, and every integration doc. Fix the grammar break in the Segment doc.
What they do well
- The robots.txt is genuinely AI-friendly with explicit
Allowdirectives for every major agent crawler and aContent-Signalheader — most B2B SaaS sites haven't gotten this far. - The Terms of Service is unusually concrete on liability caps (5,000 EUR or 6-month fees) and retention windows — most SaaS terms are vaguer.
- The PostHog and Segment integration guides, where they exist, are step-by-step and screenshot-driven — easy to follow if you can find them.
Top 3 recommendations
- Fix the front door. Host the SDK docs on a
userlens.iodomain (alias the GitBook todocs.userlens.io) and consolidate the wudpecker GitHub repos under auserlensorg — or at minimum add a "Where our docs live" callout that names every domain involved. - Publish an actual HTTP API reference with auth, endpoints, schemas, rate limits, and an OpenAPI spec. Right now the developer-facing surface area is a blog post about API versioning and a 1.5KB unmaintained PyPI package. That's an inversion of priorities.
- Reconcile SOC 2 / GDPR / data residency / retention claims across homepage,
llms.txt,/privacy-security,/privacy-policy, and Terms. Pick one true status and one true location per claim, propagate everywhere, then ship anllms-full.txtso the AI agents you've already invited in can actually answer integration questions.