Bug 🐞
ais-instant-search doesn't support insightsMiddleware
https://www.algolia.com/doc/guides/getting-insights-and-analytics/search-analytics/click-through-and-conversions/how-to/send-click-and-conversion-events-with-instantsearch/js/#connect-instantsearch-with-the-insights-middleware
Support middlewares.
Create a new props:
insightsMiddleware
3.4.2
That's right, today we haven't yet made an api in Vue InstantSearch for making this happen, however what you can do is the following for now: https://codesandbox.io/s/unruffled-solomon-ycuxr?file=/src/Insights.js
this.instantSearchInstance for adding the middleware@profhouse Did you end up getting this working? The sandbox link I couldn't get running successfully with insights.
@jonathan-bird One detail that I forgot to put in that sandbox is loading the insights client, I've now done that and it works for me (I see insights events): https://codesandbox.io/s/unruffled-solomon-ycuxr?file=/public/index.html
I've added this script to the public html before the vue scripts are loaded:
<script>
var ALGOLIA_INSIGHTS_SRC =
'https://cdn.jsdelivr.net/npm/[email protected]';
!(function (e, a, t, n, s, i, c) {
(e.AlgoliaAnalyticsObject = s),
(e[s] =
e[s] ||
function () {
(e[s].queue = e[s].queue || []).push(arguments);
}),
(i = a.createElement(t)),
(c = a.getElementsByTagName(t)[0]),
(i.async = 1),
(i.src = n),
c.parentNode.insertBefore(i, c);
})(window, document, 'script', ALGOLIA_INSIGHTS_SRC, 'aa');
</script>
That sandbox was great help thanks. I was just having a play with your sandbox and copied a lot, including api ID / key and still the same issue.
I decided to try the CURL command manually and got the response: {"status":422,"message":"Cannot process more than 20 objects in an event"}
I finally got a 200 response when I changed "perPage" to 20 from my default 40. Hmmm...
I think I'm on to something here! Although it's an automated insight "view" event type API call so I'm not sure how I can do both. I would've thought it'd just split automatically since it's not manually sent.
I ended up getting it completely working now with my per page = 40. I just catch the event and modify the payload to split into chunks of 20.
import { createWidgetMixin } from 'vue-instantsearch';
import { createInsightsMiddleware } from 'instantsearch.js/es/middlewares';
import aa from 'search-insights';
aa('init', {
appId: 'xxx',
apiKey: 'xxx',
userToken: window.gaDefaultConfig.user_id.toString()
});
function splitArrayByCount(array, chunk = 20) {
let i,
j,
tempArray = [];
for (i = 0,j = array.length; i < j; i+=chunk) {
tempArray.push(array.slice(i, i + chunk));
}
return tempArray;
}
export default {
mixins: [
createWidgetMixin({ connector: true })
],
created() {
const insightsMiddleware = createInsightsMiddleware({
insightsClient: aa,
onEvent: (event, aa) => {
const { insightsMethod, payload, widgetType, eventType } = event;
const newObjectIDPayload = splitArrayByCount(payload.objectIDs);
// Send the event to Algolia in chunks of 20
for (var i = 0; i < newObjectIDPayload.length; i++) {
let tempPayLoad = payload;
tempPayLoad.objectIDs = newObjectIDPayload[i];
aa(insightsMethod, tempPayLoad);
}
}
});
this.instantSearchInstance.use(insightsMiddleware);
},
render() {
return null;
},
};
@Haroenv are you able to add a click event into your demo? I keep finding that I get the error saying that it should be added "insightsClient" but as I recall this is the old way of doing things and now you use middleware which is what we've done.
Error in v-on handler: "Error: The `insightsClient` option has not been provided to `instantsearch`.
And that's with:
@click="insights('clickedObjectIDsAfterSearch', {
eventName: 'Add to cart',
objectIDs: [item.objectID]
})"
I can pass the window.aa to the <ais-instant-search> and it works to send them, but it just says this approach is deprecated.
Thanks for your workaround with splitting the events, I didn't know the insights api added that restriction.
For your last question, I think this is because the approach hasn't yet been updated in the documentation, sorry for that! It's meant to be using the sendEvent method, not the insights method. Unfortunately Vue InstantSearch hasn't been updated to take advantage of this. For the time being, a custom widget like this is the best approach before we make the sendEvent changes here:
<template>
<div
v-if="state"
:class="suit()"
>
<slot
:items="items"
:send-event="state.sendEvent"
>
<ol :class="suit('list')">
<li
v-for="(item, itemIndex) in items"
:key="item.objectID"
:class="suit('item')"
>
<slot
name="item"
:item="item"
:index="itemIndex"
:send-event="state.sendEvent"
>objectID: {{ item.objectID }}, index: {{ itemIndex }}</slot>
</li>
</ol>
</slot>
</div>
</template>
<script>
import { connectHitsWithInsights } from 'instantsearch.js/es/connectors';
import { createWidgetMixin, createSuitMixin } from 'vue-instantsearch';
export default {
name: 'AisHits',
mixins: [
createWidgetMixin({ connector: connectHitsWithInsights }),
createSuitMixin({ name: 'Hits' }),
],
props: {
escapeHTML: {
type: Boolean,
default: true,
},
transformItems: {
type: Function,
default(items) {
return items;
},
},
},
computed: {
items() {
return this.state.hits;
},
widgetParams() {
return {
escapeHTML: this.escapeHTML,
transformItems: this.transformItems,
};
},
},
};
</script>
and then use sendEvent in the click handler sendEvent('click'/'convert', [item], "Add to cart")
Thanks again for digging here and noticing some flaws @jonathan-bird, we will improve this experience soon
Thanks heaps @Haroenv, I'll give that a go.
I ended up getting a workaround using a click event and then using the instance, so it ended up like this:
window.instantSearchInstance.sendEventToInsights({
eventType: 'conversion',
insightsMethod: 'convertedObjectIDs',
payload: {
eventName: 'Add to cart',
index: 'sync_stock_products',
objectIDs: [productItem.dataset.objectId],
queryID: productItem.dataset.queryId
}
});
Where all of the productItem is just a data attribute on the element and I just pull it in for the click event.
Your approach is obviously the proper solution so I'll give that a go next week. I've at least got it live and collecting data now, so I'm very excited to start testing the personalisation, reordering & rules.
@Haroenv Do you know if the insights middleware does anything to the query params upon first page load?
I've had everything working for a few days well but noticed that when this.instantSearchInstance.use(insightsMiddleware); is set, my ?page=X query param gets removed. When I comment that out, it works again. Other query params (like query, brand etc all work). I use this method for state & parsing/creating URL which has been working for a year now perfectly until insights got added and can get it working but only when commenting that use() line: https://www.algolia.com/doc/guides/building-search-ui/going-further/routing-urls/vue/
Interesting that it looks to affect this method:
stateToRoute(uiState) {
const indexUiState = uiState[indexName] || {};
return {
query: indexUiState.query,
page: indexUiState.page,
brands: indexUiState.refinementList && indexUiState.refinementList.brand,
hierarchicalMenu: indexUiState.hierarchicalMenu,
range: indexUiState.range
};
},
It seems to parse from the parseURL method correctly, but then when it comes through to this stateToRoute, there is no page params. Very strange, which is why I wonder if the middleware is removing it.
I can replicate the issue by adding (I've set insightsClient to null for the sake of this to show it's not the insightsClient):
export default {
mixins: [
createWidgetMixin({ connector: true })
],
created() {
const insightsMiddleware = createInsightsMiddleware({
insightsClient: null
});
this.instantSearchInstance.use(insightsMiddleware);
},
render() {
return null;
},
};
The behaviour doesn't seem to happen when I don't set the insightsClient, but does when I set it to null or to the window.aa, or if I just comment out the instance using the middleware:
export default {
mixins: [
createWidgetMixin({ connector: true })
],
created() {
const insightsMiddleware = createInsightsMiddleware();
// this.instantSearchInstance.use(insightsMiddleware);
},
render() {
return null;
},
};
This is very odd, and not something I have seen before @jonathan-bird, do you have this behaviour too when you create an isolated sandbox or repository?
Hmm I don’t know how I can create it in a sandbox since it’s affected by
the URL so I don’t know if It’ll work that way. Do you know if there is a
way to set query Params in the sandbox?
I can share my code file with you privately though if you’d like.
the url can be set by putting a link in the body and clicking on it, or via the url bar in the sandbox
a starter is here: https://codesandbox.io/s/github/algolia/create-instantsearch-app/tree/templates/vue-instantsearch
otherwise privately is also fine, as long as it's a minimal and easy to set up repository
@Haroenv just figured it out! Give me 10 mins and I'll have a sandbox setup for you, thanks!
@Haroenv https://codesandbox.io/s/vue-instantsearch-broken-page-query-param-5z5qg?file=/src/Insights.js
To replicate, add "?page=5" to the URL, you will see it removes it.
Go to insights.js, comment out the this.instantSearchInstance.use(insightsMiddleware);, save, then add it again and you will see ?page=5 stays in the URL.
Let me know if you have any workarounds or find the cause of it, I may need
to turn insights off tomorrow if I can’t find a way to make It play nice
together as this will ruin our site being crawled as we have 15k products
so Google usually crawls a few thousand pages a day, can’t have any weird
redirects.
Thanks for your help!
I haven't yet found a reason unfortunately, but I'm looking into it @jonathan-bird
I have found the source of the bug @jonathan-bird, making a PR now
I've proposed a fix in https://github.com/algolia/instantsearch.js/pull/4655 @jonathan-bird, for the mean time you can use patch-package to apply my fix
if you use the latest version of InstantSearch.js (4.14.2) (yarn upgrade will give it) this bug is fixed, thanks for noticing it @jonathan-bird !
@Haroenv You are an absolute lifesaver!! I'll send you a virtual bottle of wine from Australia :D