ankane / ahoy.js Goto Github PK
View Code? Open in Web Editor NEWSimple, powerful JavaScript analytics
License: MIT License
Simple, powerful JavaScript analytics
License: MIT License
Allow setting extra attributes to clicks via data html attributes.
<a href="/profiles/1" id="profile_link" data-ab-test="green_button">Profile</a>
Would send abTest: "green_button"
to ahoy_events table.
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
We're loading ahoy up like this (from GTM):
<script type="text/javascript" src="//path_to_ahoy/ahoy-0.3.2.js"></script>
<script>
ahoy.configure({
cookieDomain: "ourdomain.com"
});
ahoy.trackAll();
</script>
We execute this both on our naked domain and a subdomain. So, obviously setting cookieDomain is important or we'd get double cookied and/or bad things™️ would happen.
It appears to me that this thing: https://github.com/ankane/ahoy.js/blob/master/src/index.js#L438-L442 is triggered before the configure block has had a chance to execute.
I've currently 'fixed' this by hardcoding our domain into the lib itself here: https://github.com/ankane/ahoy.js/blob/master/src/index.js#L8 and that seems to fix things up nicely.
Would it make sense to remove the documentReady block from the lib itself and give control of that to the end user to execute after configure has had a chance to run?
Hey, awesome library guys.
I was wondering if we should be concerned about uuid collisions using Math.random to generate the UUID? Based on the SO post https://stackoverflow.com/a/2117523/1177228
I have been successfully using ahoy.js 3.4 inside vuex without any issues. With the following command:
this._vm.$ahoy.track('start', { id: 'ABC' })
After upgrading to 3.5, when trying to execute the same command I get the following error:
TypeError: Object(...) is not a function
It gets thrown by this line inside the trackEventNow function
window.navigator.sendBeacon(eventsUrl(), objectToFormData(data));
I think it might be due to this object-to-formdata upgrade:
What would be the correct way to use the track funcion with the new version of the upgraded object-to-formdata library?
We install ahoy
gem and ahoy.js
on a project today to use it. So I'm looking on configuration to know how it works depending of some configs.
And I would like to know if ahoy.js
do something if cookies
is set to false
. From my code reading it looks like not. But I would like to be sure.
When using the config useBeacon: true, the events tracking (clicks / views and submits) result in an NS_ERROR_FAILURE for beacon.
Disabling this config fixes the issue.
I've tried digging further into the code to find the cause, but was unable to do so.
window.navigator.sendBeacon(eventsUrl(), serialize(data));
Seems to be the culprit in the trackEventNow() function
If you have a click event trigger ahoy.track, and that click opens a new window or tab, it will post the event twice. I think is because when window/tab loads check for eventQueue and the event is still on eventQueue.
I think the solution is to set the cookie name to ahoy_events_TIMESTAMP. So every window/tab will work on a different cookie.
I found it using ctrl + click on a anchor tag using click event.
In order to handle non-cookie authentication for API backends (and set the current_user to attach events and visits), we need to be able to add custom headers to the request being sent.
In our case, we are doing Authentication via JSON Web Token passed via either headers or URL parameters. We would need to be able to configure those headers either dynamically on every call or maybe better, after we authenticate the user frontend-side.
ahoy.trackAll(); <- how do I activate this?
my script is at
v.ezw.io
i've modified https://v.ezw.io/j1/v.js
pls help. thx
Here is the use case:
The app is a ruby rails app, that serves HTML so no real sense of a Javascript application.
I am generating a fingerprint using fingerprintjs, which returns the result with a callback. This callback sometimes returns quickly or slowly, which seems to be based on the browser. For example in chrome it returns quickly, and on Firefox it returns slowly.
And in some cases, the visit has already been created. So when I call ahoy.configure
in the callback the visit is already created and the fingerprint is never set.
A couple of thoughts:
createVisit
is exposed or a new helper method is created upsertVisit
.Other ideas? Am I thinking about this incorrectly?
So I have code that is calling ahoy from a Wordpress front-end to post to a Rails backend (part of the site is dynamically served from rails APIs).
I have ahoy.configure set as such (my API's run from /flip).
ahoy.configure({
urlPrefix: "",
visitsUrl: "/flip/ahoy/visits",
eventsUrl: "/flip/ahoy/events",
cookieDomain: null,
page: null,
platform: "Web",
useBeacon: false,
startOnReady: true
});
Sometimes, I see it working and events are being added to the database, but for click events I'm getting 404 errors where it is trying to find the events at <domain>/ahoy/events
.
Where and when should configure be called? Is it enough to call it on document.load
?
Hey, do you have tricks/gists to integrate Ahoy.js with Segment.io ?
Is there a way to properly forward visitor ID and event tracking to Ahoy.js ?
I am using Ahoy on my Rails backend and it works great, but with our new React based Frontend we'd like to use some dispatcher service like Segment.io to avoid having to dispatch events everywhere.
Hello again open source hero, ankane. 💪
Our visitParams
is not sending with trackView
. I followed the instructions in the Ruby ahoy repository and dug through the code, but I can't tell why this isn't working, and there's no documentation to explain it that I can see.
Using the example from the Ruby repository in our Vue router:
router.afterEach(route => {
// we want to send some extra stuff here
ahoy.configure({ visitParams: { referralCode: 123 } })
ahoy.trackView()
})
Nothing in visitParams
appears in the payload.
If the API ins't running on the same server i couldn't found a way to track the user of the action
I have a use-case where I have trackClicks()
turned on, but for certain interactions, I want to fire my own event, not just a generic $click
. I would prefer not to get double events, so I need a way to disable the overall trackClicks functionality for this part of my page.
So I made the onEvent
function ignore the matched element if the matched element also matches on [data-no-track] *, [data-no-track]
. This will let me either put a data-no-track attribute on the <a>
itself or in a parent of the <a>
.
I would be happy to submit a PR if you find this functionality useful.
Hello, our team uses your lib and we had some difficulties with the default value of visitTtl
and visitorTtl
, mainly because of visitTtl
.
Basically, our session token expires in thirty days, while the ahoy_visit
cookie expires in four hours. After four hours, the ahoy_visit
cookie is renewed and our backend loses control of the events because a new visit_token
is created.
Our suggestion is to keep the default valves, but create a option to configure these values on the configure
function.
I will send a PR with the code change and, if it makes sense, let me know and I will update the documentation as well.
Hi @ankane,
i'm using your amazing ahoy.js
It doesn't seem like a problem, but just to be sure. Is this a bug or should it be like this? So i tried to configure my ahoy.js like this
ahoy.configure({
urlPrefix: process.env.VUE_APP_BASE_API,
visitsUrl: "//ahoy/visits",
eventsUrl: "//ahoy/events",
page: "landing-page",
platform: "Web",
useBeacon: true,
startOnReady: true,
trackVisits: true,
cookies: true,
cookieDomain: null,
headers: {},
visitParams: {},
withCredentials: true,
visitDuration: 4 * 60, // 4 hours
visitorDuration: 2 * 365 * 24 * 60 // 2 years
})
on visitsUrl
and eventsUrl
should always use double //
if I use single /
it doesn't send any action to the backend. and by the way my env variable contains something like this http://localhost:3000
can you clarify to help me? Thanks in advance
Hello,
We have a React frontend app that relies on the no-jquery branch of your gem which is a bit outdated now (and we have problems with duplication of cookies with httpOnly/sameSite, etc). Do you plan on maintaining it or should we drop it to use something else ?
I've been using the ahoy.js library to create ahoy events on a rails server on a different domain which has the ahoy gem configured. The events are being created successfully. However, I need to send the cookies on the request, because the server gets some extra data from that.
The above requires the following option to be set on the ajax request:
xhrFields: {
withCredentials: true
}
Is there an option on ahoy.js to make this work?
I'm setting ahoy config in this way:
ahoy.configure({
urlPrefix: 'http://otherdomain.com'
});
Currently, the ahoy_visit cookie is only renewed if a server API is called, which the AhoyController
on the server side extends the ahoy_visit
cookie's expiration date.
This becomes problematic when the user stays idle the page, but whose actions should still be considered to belong to the same ahoy visit when they resume.
Could we have an option in ahoy to start a timer that automatically extends the ahoy_visit
cookie's expiration date?
Hello folks.
I've struggling with the NextJS and Ahoy. Besides to follow this I wasn't able to get it work so far.
I tried to import the lib in different ways like the old issue talk about but there was no good luck. Has someone walked through this?
I'm a fresher. I'm having problem using Ahoy.js.
I have 2 sample file HTML include Ahoy.js.
Sample A:
<a href="B.html"> <img src='a.jpg'> </a>
Sample B:
<button>Add Cart</button>
I click a tag, when redirect to 'B.html', maybe eventQueue is still saved from A.html, so it should be duplicated event when send request via Ajax.
Can anyone help me??
Thanks you!.
We noticed that ahoy_events on different days have the same visit_id which are attributed to ahoy_visits.
Based on the text from the Readme, wouldn't events have different visit IDs if it's been over four hours?
Readme:
The visit token expires after 4 hours, in which a new visit is created. Visits are useful for tracking metrics like monthly active users. The visitor token expires after 2 years.
.
On a side note, we have some ahoy_event records from last month that have the same visit_id as records created today. How are vistors being tracked since we have no users accounts (the site doesn't have a login function), set mask_ips to True, and set cookies to False?
Ideas
navigator.sendBeacon
by defaultsetProperties
methodTrack clicks has the href.
when "input[type=submit]"
could have a property form_action
=> getClosest(this, "form").action
As far as I investigate, there are differences in behavior as follows. I want to track click events in all a-tags, is there a way to do that?
# Click events are tracked
<a>click</a>
# Click events are not tracked
<a><span>click</span></a>
Is there a special reason for this?
Ahoy is working correctly 99% of the time, but once in a while we are getting "no implicit conversion of Array into String" errors
Instead of {"name": "My Name", "properties": { ... }}
it is posting that wrapped as an array ([{"name": "My Name", "properties": { ... }}]
) to /ahoy/events
We have seen occurrences on windows and mac, chrome and firefox.
It seems like every pageview of an affected user will trigger the error.
Thanks for the useful gem!
Why did you remove #trackAll in the latest ahoy.js? (just curious)
One more question. Why did you stop mentioning ahoy.js on ankane/ahoy/README.md?
Just noticed when testing some analytics locally, the beacon did not fire.
https://github.com/easylist/easylist/blob/master/easyprivacy/easyprivacy_general.txt#L487
Seems to be, it was added 13 days ago.
To make analytics still work, if that is desired, then one needs to change the path:
# config/initializers/ahoy.js
Ahoy.api = false
# config/routes.rb
mount Ahoy::Engine => "/ahoyyy"
# app/.../ahoy.js
ahoy.configure({
visitsUrl: "/ahoyyy/visits",
eventsUrl: "/ahoyyy/events",
})
Hi @ankane
Really thanks for your awesome work both client and server.
I use this package with nextjs and there was an issue when importing this module.
pages/index.js
...
import ahoy from 'ahoy.js'
...
1. dynamic import
window is not defined
is well known issue and I tried the well-known solutions.
...
import dynamic from 'next/dynamic'
const ahoy = dynamic(() => import('ahoy.js'), {
ssr: false
})
then, in componentDidMount
call ahoy method.
...
componentDidMount () {
ahoy.track('test')
}
2. require module in componentDidMount
componentDidMount () {
this.Ahoy = require('ahoy.js').default
console.log('Ahoy!', this.Ahoy.track('Hello!'))
}
=> This worked. (Post 501 error is not a problem)
3. Final Code
somewhere in project
ex: utils/customAhoy.js
import Cookie from 'js-cookie'
const dev = process.env.NODE_ENV !== 'production'
const baseURL = dev ? 'http://api.localhost:3000' : 'https://api.example.com'
const isServer = (typeof window === 'undefined')
let ahoy
if (!isServer) {
ahoy = require('ahoy.js').default
ahoy.configure({
urlPrefix: '',
visitsUrl: `${baseURL}/ahoy/visits`,
eventsUrl: `${baseURL}/ahoy/events`,
page: null,
platform: 'Web',
useBeacon: true,
startOnReady: true,
trackVisits: true,
cookies: false,
cookieDomain: null,
headers: {'Authorization': `Bearer ${Cookie.get('accessToken')}`},
visitParams: {},
withCredentials: true
})
}
export default ahoy
somewhere in project you want to use ahoy
ex: index.js
import React from 'react'
/* import configured ahoy */
import ahoy from 'utils/customAhoy'
export default class Index extends React.Component {
componentDidMount () {
ahoy.trackAll()
}
render () {
return (
<div />
)
}
}
I just reported this if someone has same trouble. If someone have a better solution, please let me know.
Thanks.
Hi there, I'm trying to get UTM parameters recorded in Ahoy using this library. They always appear blank, even though trackView()
stores the full URL correctly in the visits
table.
I see some information about landing_page
and how a POST
to /ahoy/visits
sends this along with the tracking tokens.
However, watching my Chrome network tab, the only API calls made are to /ahoy/events
.
Has this behaviour changed, and the README is not up to date?
Hi! first of all thanks for this useful tool.
I was having some troubles finding out why on the first page load, visitsUrl was pointing to the default URL 'ahoy/visits' and not the one I set up with the configure method. I find out that the issue is related to the documentReady function call at the end of library source code.
documentReady(function() {
if (config.startOnReady) {
ahoy.start();
}
});
return ahoy;
The problem is synchronization, by the time the library module is required, is very likely that the DOM content has already been loaded, calling the documentReady function with the default parameters that are inside the library source code (where startOnReady. is set to true, mine is set to false). Due to some requirements I'm using require.js that is being loaded after the HTML body tag and it's difficult for me to change this.
I writing this issue also as a reminder, I will like to make a pull request offering an alternative solution when i have some time. I can just change the default config object, but it would be better if it supports my use case.
Let me know what you think or if there's another step or solution that I'm missing.
Thanks!
Hi @ankane, just wanted to make a note that NPM repo is still showing ahoy.js at version 0.2.0, rather than the updated 0.2.1 version (https://www.npmjs.com/package/ahoy.js).
I am sorry if this is actually a JS question and not an Ahoy one, I'm a beginner at both of them.
I would like to track certain elements of my page, so I bind a function to their "onClick" to perform an ahoy.track(...). However, nothing happens! If I go to Firefox's console and write ahoy.track("bla",{}). If I click the 'network' tab, I see that no http post request is sent to (xxx/ahoy/event).
When I click enter, the only thing that happens is the
Am I understanding something wrong? Shouldn't ahoy.track
send a post to the server?
Thanks!
Chrome just changed the way they handle cross-origin sendBeacon
requests.
https://bugs.chromium.org/p/chromium/issues/detail?id=490015
From what I understand, they don't want cross origin requests to be able to send JSON, but they are allowed to send plaintext. It will be up to the server to deal with the difference in format and deal with the request accordingly.
We got dinged with this in our implementation, because right now we host the JS on our www
domain, and send CORS requests to our track
subdomain. Our current plan is to change the way we host the file so that the CORS isn't required, but I'm curious if you think that this is worth updating the library to handle this scenario?
Our frontend Ionic web app is running on a different server than our backend Rails API, trying to get Ahoy Rails wired up to post events however getting Cross-Origin Read Blocking
error.
Cross-Origin Read Blocking (CORB) blocked cross-origin response http://localhost:3000/ahoy/events with MIME type application/json.
Is it possible for ahoy.js to track events to a different server than Ahoy Rails? Would I need to expose my own API endpoint to receive the track events from ahoy.js?
First of all, I know there's a workaround #35
But it's a workaround -- we still need to do dynamic
import, which is not ideal because we lose the benefits of React Server Component (RSC).
I'm happy to open a PR to address this issue permanently - but since I'm not familiar with ahoy.js
's architecture, I would like to consult people who are familiar with it.
The core issue is that window
object, in SSR-centric environment like Next.js, is not always defined. RSC generation runs on the server - where window
object is undefined. I hope I'm not oversimplifying this, but the solution is to do if (typeof window === 'undefined') return
such that ahoy
doesn't run server-side. Would this solution be viable?
Thanks
Hi there! Love using ahoy, I think it's a great product. Thanks to all who has worked on it.
I did a quick search through the issues but wasn't able to come up with any relevant questions, so here goes:
Using tailwind CSS adds a lot of classes to our button elements. When I click on a button this is the tracking JSON that gets pushed to ahoy.
[
{
"name":"$click",
"properties":{
"tag":"a",
"class":"appearance-none cursor-pointer flex focus:border-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 font-sans font-medium rounded-full transition ease-out duration-300 text-2xl justify-center px-4 mt-6 mr-6 md:mt-8 md:mr-8 custom-class",
"page":"/redacted/redacted",
"text":"close",
"href":"http://redacted.com"
},
"time":1643737795.999,
"id":"fd57268c-34f8-4726-a00a-f4d96d320df6",
"js":true
}
]
Specifically what I am interested in is removing a lot of the cruft that comes along with the class
attribute.
I wonder if we should give people the option to filter out certain classes that provide no value to tracking? In this case I'd want to filter out every class except custom-class
at the end.
So, desired tracking output would be:
[
{
"name":"$click",
"properties":{
"tag":"a",
"class":"custom-class",
"page":"/redacted/redacted",
"text":"close",
"href":"http://redacted.com"
},
"time":1643737795.999,
"id":"fd57268c-34f8-4726-a00a-f4d96d320df6",
"js":true
}
]
Thanks in advance!
getting TypeError: Illegal invocation
The stack trace’s top layer stops at window.navigator.sendBeacon(eventsUrl(), index_module_1(data)
which comes from ahoy.js
Calling function is ahoy.trackView()
Errors are not confined to any particular browser or device.
In reference to #64
This issue is currently causing a lot of TypeError: Illegal Invocation error metrics. I don't think it will be very easy to provide a way to reproduce but would it be possible to improving the visibility into the circumstances surrounding the exceptions being thrown? The error it self doesn't give very much info on why it's taking place. Would it be possible to add a try catch to give useful debug output and rethrow, such as an output of eventsUrl() and data and index_module_1's return in order to help us with debugging the Illegal Invocations?
Hello, i am getting issues with ahoy, I am including ahoy.js in the DOM. And when it is loaded and app is loaded I am doing
ahoy.configure(config) // my configuration
then I do
ahoy.trackView();
ahoy.trackClicks("a, button, input[type=submit]");
ahoy.trackSubmits("form");
ahoy.trackChanges("input, textarea, select");
But first POST requests goes to wrong URL (the default ones from ahoy.js) and I am getting 404. Can I avoid this somehow?
We're experimenting with Ahoy. One thing we've noticed is that using the default submit tracking sometimes conflicts with custom forms we have with an onSubmit
event. We've worked around this by manually hooking those forms up to fire ahoy.track
as part of their onSubmit
function, but part of doing so involved copying cleanObject
into our own code since it's not readily available.
Would you be open to a PR that promoted some of the private helper functions to exports? One possible idea here would be to extract the code in iteration within trackSubmits
https://github.com/ankane/ahoy.js/blob/master/src/index.js#L454-L457 into its own trackSubmit
function so that it could be individually applied to forms.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.