The Segment connector has improved, so invalid events and errors that the connector didn’t display now appear. Your current valid events are still here.
If you already have integrated Segment on your website and send events to Segment, you can configure your Segment dashboard to redirect the events to Algolia.
There are two steps to integrate Segment with Algolia:
- Enable the “Algolia” destination on your Segment dashboard.
- Add extra Algolia-related data to events sent to Segment.
Enable “Algolia” destination on your Segment dashboard
On your source, click the “Add Destination” button.
From the destination catalog, search for and add “Algolia”.
Copy your Application ID and Search-Only API Key from your Algolia dashboard and paste there.
Enable clickAnalytics
First, you need to enable clickAnalytics
to retrieve queryID
in your search response.
1
2
3
4
5
6
| index.search('query', {
userToken: 'user-1',
clickAnalytics: true
}).then(({ hits, queryID }) => {
console.log(hits, queryID);
})
|
1
2
3
4
| instantsearch.widgets.configure({
clickAnalytics: true,
userToken: 'user-1'
});
|
1
2
3
4
| <Configure
clickAnalytics={true}
userToken={'user-1'}
/>
|
1
2
3
4
| <ais-configure
:click-analytics.camel="true"
user-token.camel="user-1"
/>
|
1
2
3
| <ais-configure
[searchParameters]="{ clickAnalytics: true, userToken: 'user-1' }"
></ais-configure>
|
Required properties
With Segment integrated, you probably have code that looks something like the following to send events to Segment:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| analytics.track('Product Clicked', {
product_id: '507f1f77bcf86cd799439011',
sku: 'G-32',
category: 'Games',
name: 'Monopoly: 3rd Edition',
brand: 'Hasbro',
variant: '200 pieces',
price: 18.99,
quantity: 1,
coupon: 'MAYDEALS',
position: 3,
url: 'https://www.example.com/product/path',
image_url: 'https://www.example.com/product/path.jpg',
})
|
Algolia requires the following fields that aren’t a part of the regular specifications from Segment:
index
: string
(required)
eventType
: 'view' | 'click' | 'conversion'
(required)
queryID
: string
objectIDs
: string[]
positions
: number[]
filters
: Array<{ type: string; value: string; }>
or string[]
(${type}:${value}
, for example, brand:apple)
This is an example of the final payload:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| analytics.track('Product Clicked', {
product_id: '507f1f77bcf86cd799439011',
sku: 'G-32',
category: 'Games',
name: 'Monopoly: 3rd Edition',
brand: 'Hasbro',
variant: '200 pieces',
price: 18.99,
quantity: 1,
coupon: 'MAYDEALS',
position: 3,
url: 'https://www.example.com/product/path',
image_url: 'https://www.example.com/product/path.jpg',
index: 'my-algolia-index',
eventType: 'click',
queryID: 'fd0bbaadc287937s7671d00f1d053b88',
objectID: '131280270'
});
|
You can get all those properties like the following:
1
2
3
4
5
6
7
8
| index.search('query', {
userToken: 'user-1',
}).then(({ hits, queryID }) => {
hits.map((hit, index) => {
const position = index + 1; // position starts from 1
const objectID = hit.objectID;
});
});
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| // Required: InstantSearch.js >= 4.8.3
search.use(
instantsearch.middlewares.createInsightsMiddleware({
insightsClient: null,
onEvent(event) {
const { widgetType, eventType, payload, hits } = event;
if (widgetType === "ais.hits" && eventType === "view") {
analytics.track("Product List Viewed", {
index: payload.index,
eventType: 'view',
queryID: payload.queryID,
objectIDs: payload.objectIDs,
positions: payload.positions,
// the rest
});
} else if (/* ... */) {
// ...
}
},
})
);
// index
// eventType
// queryID
// objectIDs
// positions
// filters
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| function debounce(fn, delay) {
let timerId;
return function(...args) {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
fn(...args);
timerId = null;
}, delay);
};
}
const debouncedHitsRender = debounce(({ hits }) => {
if (hits.length > 0) {
analytics.track("Product List Viewed", {
index: '<index-name>',
eventType: 'view',
queryID: hits[0].__queryID,
objectIDs: hits.map(hit => hit.objectID),
positions: hits.map(hit => hit.__position),
// the rest
});
}
}, 500);
const SendViewEvent = connectHits((...args) => {
debouncedHitsRender(...args);
return null;
});
// ...
const Hit = ({ hit }) => (
<article>
<h1>{hit.name}</h1>
<button
onClick={() =>
analytics.track("Product Clicked", {
index: '<index-name>',
eventType: 'click',
queryID: hit.__queryID
objectID: hit.objectID,
position: hit.__position,
// the rest
})
}
>
Add to favorite
</button>
</article>
);
// ...
<Configure clickAnalytics />
<SendViewEvent />
<Hits hitComponent={Hit} />
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| <!-- Required: Vue InstantSearch >= 3.7.0 -->
<template>
<ais-instant-search
:index-name="<index-name>"
:search-client="searchClient"
:middlewares="middlewares"
>
<!-- widgets -->
</ais-instant-search>
</template>
<script>
import {
createInsightsMiddleware,
} from 'instantsearch.js/es/middlewares';
const insightsMiddleware = createInsightsMiddleware({
insightsClient: aa,
onEvent(event) {
const { widgetType, eventType, payload, hits } = event;
if (widgetType === "ais.hits" && eventType === "view") {
analytics.track("Product List Viewed", {
index: payload.index,
eventType: 'view',
queryID: payload.queryID,
objectIDs: payload.objectIDs,
positions: payload.positions,
// the rest
});
} else if (/* ... */) {
// ...
}
}
});
export default {
data() {
return {
// ...
middlewares: [insightsMiddleware]
}
},
}
</script>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
| import { Component, OnInit, forwardRef, Inject } from '@angular/core';
import { BaseWidget, NgAisInstantSearch } from 'angular-instantsearch';
import { connectHits } from 'instantsearch.js/es/connectors';
function debounce(fn, delay: number) {
let timerId;
return function(...args) {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
fn(...args);
timerId = null;
}, delay);
};
}
const trackView = debounce(hits => {
if (hits.length > 0) {
analytics.track('Product List Viewed', {
index: '<index-name>',
eventType: 'view',
queryID: hits[0].__queryID,
objectIDs: hits.map(hit => hit.objectID),
positions: hits.map(hit => hit.__position),
// the rest
});
}
}, 500);
@Component({
selector: 'app-tracker',
template: ``
})
export class TrackerComponent extends BaseWidget implements OnInit {
public state: {
hits: any[];
};
constructor(
@Inject(forwardRef(() => NgAisInstantSearch))
public instantSearchParent
) {
super('Tracker');
}
public ngOnInit() {
this.createWidget(connectHits, {});
super.ngOnInit();
}
updateState = state => {
if (!state.hits || state.hits.length === 0) {
return;
}
trackView(state.hits);
};
}
// ...
<ais-configure [searchParameters]="{ clickAnalytics: true }" />
<ais-hits>
<ng-template let-hits="hits" let-results="results">
<div *ngFor="let hit of hits">
<ais-highlight attribute="name" [hit]="hit"></ais-highlight>
<button
(click)="
analytics.track('Product Clicked', {
index: '<index-name>',
eventType: 'click',
queryID: hit.__queryID
objectID: hit.objectID,
position: hit.__position,
// the rest
})
"
>
Favorite
</button>
</div>
</ng-template>
</ais-hits>
|
Debugging events
First, check your events on the Segment dashboard.
The green box showing “200 OK” means Segment delivered the event to Algolia.
Now, you can check the events on the Algolia dashboard. Go to the Events Debugger to see more information about your events.
Using Algolia Personalization with Segment
If you pass a userId
to Segment (using analytics.identify()
), you may want to pass the same identifier to Algolia to allow personalized search results. All you need to do is pass the userToken
parameter with your search.
1
2
3
4
5
6
| index.search('query', {
userToken: 'user-1',
enablePersonalization: true
}).then(({ hits }) => {
console.log(hits);
})
|
1
2
3
4
| instantsearch.widgets.configure({
enablePersonalization: true,
userToken: 'user-1'
});
|
1
2
3
4
| <Configure
enablePersonalization={true}
userToken={'user-1'}
/>
|
1
2
3
4
| <ais-configure
:enable-personalization.camel="true"
user-token.camel="user-1"
/>
|
1
2
3
| <ais-configure
[searchParameters]="{ enablePersonalization: true, userToken: 'user-1' }"
></ais-configure>
|