{"id":15649695,"url":"https://github.com/ankane/ahoy_guide","last_synced_at":"2026-02-22T02:34:21.196Z","repository":{"id":17044647,"uuid":"19809029","full_name":"ankane/ahoy_guide","owner":"ankane","description":"A foundation of knowledge and libraries for solid analytics","archived":false,"fork":false,"pushed_at":"2018-07-19T09:22:04.000Z","size":13,"stargazers_count":44,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-17T19:49:12.537Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ankane.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-05-15T06:34:06.000Z","updated_at":"2025-08-31T17:23:59.000Z","dependencies_parsed_at":"2022-07-25T21:09:09.286Z","dependency_job_id":null,"html_url":"https://github.com/ankane/ahoy_guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ankane/ahoy_guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fahoy_guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fahoy_guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fahoy_guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fahoy_guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ankane","download_url":"https://codeload.github.com/ankane/ahoy_guide/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ankane%2Fahoy_guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29703773,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T23:35:04.139Z","status":"online","status_checked_at":"2026-02-22T02:00:08.193Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T12:31:06.051Z","updated_at":"2026-02-22T02:34:21.108Z","avatar_url":"https://github.com/ankane.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ahoy\n\n:fire: A foundation of knowledge and libraries for solid analytics\n\nBest practices for:\n\n- tracking visits, events, emails, and referrals\n- scaling storage\n- funnels, cohorts, and LTV calculations\n- experiments like split tests\n- and much more\n\nDesigned to work with any progamming language and any device.\n\nNever build an analytics platform from scratch again.\n\nThis is a work in progress, built for the open-source community.  If you have great practices, articles, or videos, [please share](https://github.com/ankane/ahoy_guide/issues/new).\n\n:warning: Everything below is scattered and probably makes no sense\n\n## Outline\n\n- Intro\n- The Perfect Platform\n- People\n- Qualitative Feedback\n- Funnels\n- Split Tests\n- Web\n  - Landing page\n    - Acquisition\n    - Funnels\n    - Experiments\n  - Product\n    - Same as above\n- iOS\n  - Same as above\n- Android\n  - Same as above\n- Emails\n- Referrals\n- Load Times\n- Storage\n- Privacy\n- HTTP Spec\n\n## Entities\n\n### Visitor\n\nVisitors have properties\n\n### Visit (session)\n\nA visit belongs to a visitor.  Users can have visits through authentication events.\n\nA visit provides:\n\n- a way to attach events that happened before sign in\n- how someone arrived at the website or app\n- a rough idea of location for local services\n- information about the technology (browser, screen size, OS version), which you can use this to tailor your product to users\n\n### Event\n\nEvents are actions a person performs.\n\nEvents have a visit (from which you can get the visitor) possibly a user.\n\n### User\n\nUsers are authenticated visitors\n\nUsers have properties\n\n## Technical Notes\n\nReferences to “unique id” in this guide refer to a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier). These should be stored as a 128-bit number, not a string (except for logs).\n\nVisitors and visits should be given a unique id *on the server* for web apps and stored in cookies.\n\n## People\n\nTwo users viewing a page is different than one user viewing it twice.  This is critical for funnels and experiments.\n\nThere are two type of people:\n\n- Users - authenticated\n- Visitors - anonymous\n\n## Qualitative Feedback\n\n- [Peek](https://peek.usertesting.com/) - free!\n- [Session recording](https://www.inspectlet.com)\n\n## Funnels\n\nIntent is key\n\nSegment by:\n\n- mobile vs desktop\n- channel\n- experiment\n\n## Split Tests\n\nCommonly called split tests or A/B tests\n\n- [How Not To Run An A/B Test](https://www.evanmiller.org/how-not-to-run-an-ab-test.html)\n- [Why multi-armed bandit algorithm is not “better” than A/B testing](https://visualwebsiteoptimizer.com/split-testing-blog/multi-armed-bandit-algorithm/) - time is $$$\n- [Sample Size Calculator](https://www.evanmiller.org/ab-testing/sample-size.html)\n- [Experiments at Airbnb](https://nerds.airbnb.com/experiments-at-airbnb/)\n- [Bayesian AB Testing](https://developers.lyst.com/data/2014/05/10/bayesian-ab-testing/)\n\nStart with big changes (exploration), not button colors\n\nUse same tracking as events for conversions\n\nSegment key funnels by experiment variation\n\nSplit tests are special properties attached to visitors or users.\n\nVariation membership should be stored.  They should be looked up by user id (first), then visitor id.\n\nIf there is a user but only a split test variation for the visitor, the user should use the same variation.\n\nIt should be easy for developers to test variations.\n\n## Web\n\n### Visits\n\nThere are two ways to tell where a visitor has come from:\n\n- the `Referer` header\n- query parameters, like `utm_source`\n\nWhen a user clicks on a link, most browsers set the `Referer` header with the URL of the previous page.  From this, you can extract:\n\n- the page\n- search keywords - thanks to [great libraries](https://github.com/snowplow/referer-parser)\n\n**TODO:** Explain how [different browsers handle redirects](https://stackoverflow.com/questions/2158283/will-a-302-redirect-maintain-the-referer-string) and note about [HTTPS -\u003e HTTP](https://webmasters.stackexchange.com/questions/47405/how-can-i-pass-referrer-header-from-my-https-domain-to-http-domains)\n\nThere are a few things you can calculate about the visitor:\n\n- estimated location from IP address\n- browser, OS, and device model from user agent\n\nClient libraries have access to more information, like:\n\n- screen size\n- pixel density (retina) - does this really matter?\n\nBe sure to exclude bots from your metrics - some like Googlebot run JavaScript.\n\n### Landing Page\n\nThe landing page is one of the most important pages of your website.\n\nWhen an unauthenticated visitor lands on your site, there are a few things that could happen:\n\n- register (success!)\n- sign in\n- bounce\n\n**TODO:** Note about multiple authentication strategies (email, [Facebook](https://developers.facebook.com/docs/facebook-login/permissions/v2.0#optimizing), Google, etc)\n\n**Best practice:** For third-party services, ask for the miminum number of permissions needed\n\n#### Authenticated Visitors\n\nIf a visitor is authenticated, do **not** show them the landing page with a “Customer Login” link.  Drop them right into your product.\n\n**Best practice:** Keep users signed in between visits - unless you run a banking website of course\n\n## iOS\n\n- [Link to App Store](https://stackoverflow.com/a/2337601/1177228)\n- [Smart App Banners](https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html)\n\n## Android\n\n- [Link to Play Store](https://developer.android.com/distribute/googleplay/promote/linking.html)\n- [Link with referrer](https://developers.google.com/analytics/devguides/collection/android/v2/campaigns#google-play-implement)\n\n## Storage\n\nStart simple and scale as needed - “premature optimization is the root of all evil”\n\n- logs (not queryable)\n  - backup to [S3]\n- database\n  - PostgreSQL, Redis, Logstash, Fluentd\n- distributed data stores\n  - Hadoop, Cassandra, [Amazon Redshift]\n\n[not open source]\n\n**TODO:** Recommendations for starting, scaling, and scaling again\n\n## Email\n\nGive each message a unique id.\n\n- Track opens and clicks\n- One-click unsubscribe - don't make users confirm or sign in\n- Give the option to resubscribe or manage other lists\n- Use your own unsubscribe link rather than rely on your email server\n\n**TODO:** What emails to send, when to send them\n\nExperiment with the message, time of day, triggers\n\n## Referrals\n\nHow to track referrals correctly\n\n## Load Times\n\n[Latency matters](http://highscalability.com/latency-everywhere-and-it-costs-you-sales-how-crush-it)\n\n- Amazon - every 100ms cost them 1% in sales\n- Google - an extra half second dropped search traffic by 20%\n\nNo one ever wants a slow service\n\nHow to instrument load times: Give each request a unique id and record the time the:\n\n- request starts\n- server completes request\n- JavaScript says ready\n\nTricks:\n\n- Limit redirects\n\nAcceptable tresholds\n\n[Better SEO?](https://unbounce.com/conversion-rate-optimization/a-fast-web-site-increases-conversions/)\n\n## Privacy\n\nThings not to do\n\n- [supercookies](https://mashable.com/2011/09/02/supercookies-internet-privacy/)\n- [device fingerprinting](https://panopticlick.eff.org/)\n\nSection on Do Not Track\n\n## HTTP Spec\n\n### Visits\n\nA `POST` request is sent with:\n\n- visit_token\n- visitor_token\n- referrer\n- landing_page\n\nThe server can capture:\n\n- ip\n- user_agent\n- user - from app authentication\n\nAnd calculate things like:\n\n- referring_domain and search_keyword from referrer\n- utm_source, utm_medium, utm_term, utm_content, and utm_campaign from landing_page\n- city, region, and country from ip\n- browser, os, and device_type from user_agent\n\n### Events\n\nA `POST` request is sent with:\n\n- name\n- properties\n- time\n\nThe server can capture:\n\n- visit_token - from cookies\n- user - from app authentication\n\nAs a precaution, the server should reject times that do not match:\n\n```\n1 minute ago \u003c time \u003c= now\n```\n\n## Libraries\n\n### Client Tracking\n\nWorks with any backend\n\n- [JavaScript](https://github.com/ankane/ahoy.js)\n- iOS (soon)\n- Android (soon)\n\n### Server Tracking + Backend\n\n- [Ruby](https://github.com/ankane/ahoy)\n- Others (help make this possible)\n\n### Email\n\n- [Ruby](https://github.com/ankane/ahoy_email)\n- Others (help make this possible)\n\n### Experiments, Funnels, Cohorts, More\n\n- Coming soon\n\n## Great Content\n\n- [Startup Metrics for Pirates](https://www.youtube.com/watch?v=irjgfW0BIrw)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankane%2Fahoy_guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fankane%2Fahoy_guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fankane%2Fahoy_guide/lists"}