{"id":10488,"library":"ahoy.js","title":"Ahoy.js","description":"Ahoy.js is a client-side JavaScript analytics library designed for simple and powerful visit and event tracking. It currently stands at version 0.4.5 and is actively maintained, though a specific release cadence isn't defined. The library's core function is to capture user interactions, such as unique visits, page views, clicks, submits, and custom events, sending this raw data via `POST` requests to a configurable backend endpoint. A key differentiator is its backend-agnostic design, allowing developers to integrate it with any server-side technology, including a dedicated Ruby gem for Rails applications. It automatically manages visit and visitor tokens (expiring after 4 hours and 2 years, respectively) and provides comprehensive data points like referrer, landing page, and event properties, which can be further enriched on the server with IP, user agent, and authentication details. The library also offers robust configuration options for URL endpoints, cookie management, cross-domain tracking, and debug logging.","status":"active","version":"0.4.5","language":"javascript","source_language":"en","source_url":"https://github.com/ankane/ahoy.js","tags":["javascript","analytics","locations","referral"],"install":[{"cmd":"npm install ahoy.js","lang":"bash","label":"npm"},{"cmd":"yarn add ahoy.js","lang":"bash","label":"yarn"},{"cmd":"pnpm add ahoy.js","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Ahoy.js primarily uses ES Modules for package imports. Direct `require()` is typically incorrect for modern bundlers and Node.js environments unless a specific CJS build is targeted.","wrong":"const ahoy = require('ahoy.js');","symbol":"ahoy","correct":"import ahoy from 'ahoy.js';"},{"note":"When included directly via a `<script>` tag in an HTML document, the `ahoy` object becomes globally available in the browser window.","symbol":"ahoy","correct":"<script src=\"path/to/ahoy.js\"></script>\n<script>\n  ahoy.track('Page Load');\n</script>"}],"quickstart":{"code":"ahoy.configure({\n  cookieDomain: \"example.com\", // Use for tracking across subdomains (e.g., app.example.com, blog.example.com)\n  withCredentials: true,       // Essential for sending cookies across different domains/subdomains for authentication\n  visitsUrl: \"/api/analytics/visits\", // Customize endpoint for visit tracking\n  eventsUrl: \"/api/analytics/events\"  // Customize endpoint for event tracking\n});\n\n// Enable debug logging in the browser console\nahoy.debug();\n\n// Track a custom event with properties\nahoy.track(\"Product Viewed\", {\n  productId: \"SKU123\",\n  category: \"Electronics\",\n  price: 499.99\n});\n\n// Track a page view, automatically capturing URL and title\nahoy.trackView();\n\n// Track clicks on specific CSS selectors\nahoy.trackClicks(\".add-to-cart-button, #checkout-link\");\n\n// Track form submissions on specific CSS selectors\nahoy.trackSubmits(\"#newsletter-signup-form\");\n\n// To force a new visit for testing (requires page reload)\n// ahoy.reset();\n// window.location.reload();\n","lang":"javascript","description":"This quickstart demonstrates how to configure Ahoy.js for various tracking scenarios, including custom event tracking, page views, clicks, and form submissions, along with essential cross-domain and debugging settings."},"warnings":[{"fix":"For specific change tracking needs, use `ahoy.track()` with a custom event name and manually attach event listeners to relevant input fields.","message":"The `ahoy.trackChanges()` method is deprecated and should no longer be used for tracking input field changes.","severity":"deprecated","affected_versions":">=0.4.0"},{"fix":"Ensure you have a server-side implementation (e.g., a custom API endpoint or the Ahoy gem for Rails) configured to receive `POST` requests at `/ahoy/visits` and `/ahoy/events` (or custom configured URLs).","message":"Ahoy.js is a client-side library and requires a backend server to receive, process, and store analytics data. It is not a standalone analytics solution.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Configure Ahoy.js with `ahoy.configure({ cookieDomain: 'yourdomain.com' });` to ensure cookies are shared across all subdomains.","message":"When tracking user activity across multiple subdomains (e.g., `www.example.com` and `blog.example.com`), the `cookieDomain` configuration must be explicitly set to the top-level domain.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Enable credential sending with `ahoy.configure({ withCredentials: true });`. Also, ensure your server-side CORS policy allows `Access-Control-Allow-Credentials: true` and appropriate `Origin` headers.","message":"If your Ahoy.js client is hosted on a different domain or subdomain than your analytics backend, and you rely on cookies for user authentication, `withCredentials` must be set to `true`.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Implement strict server-side validation for the `time` property of incoming events. A common recommendation is to only accept events where `(server_time - 1 minute) < client_time <= server_time`.","message":"Ahoy.js sends event `time` from the client. The server *must* validate this timestamp to prevent clients from sending manipulated or fraudulent historical/future events.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Verify that your backend server is running and accessible at the specified URL paths (`/ahoy/visits` and `/ahoy/events` by default). Check for firewall rules, DNS resolution, and correct `urlPrefix` configuration.","cause":"The configured `visitsUrl` or `eventsUrl` does not point to an accessible or running backend service, or a network issue is preventing connection.","error":"POST https://yourdomain.com/ahoy/visits net::ERR_CONNECTION_REFUSED"},{"fix":"Ensure your server-side framework (e.g., Rails, Express.js, etc.) has routes configured to accept `POST` requests at the URLs specified in `ahoy.configure()` and that these routes lead to appropriate controllers or handlers.","cause":"Your backend application does not have the necessary routes defined to handle `POST` requests to the `/ahoy/visits` or `/ahoy/events` endpoints.","error":"Failed to load resource: the server responded with a status of 404 (Not Found)"},{"fix":"On the server, confirm that the authenticated user's ID is being extracted from the request (e.g., from a session, JWT, or other authentication mechanism). If operating across different domains/subdomains, ensure `ahoy.configure({ withCredentials: true });` is set on the client, and your server is configured for CORS with credentials.","cause":"The server-side application is not correctly capturing the authenticated user from the request, or `withCredentials` is not enabled for cross-origin requests, preventing session cookies from being sent.","error":"Analytics data is recorded, but user-specific information (like `user_id`) is missing in the backend."}],"ecosystem":"npm"}