Skip to content

Commit e455257

Browse files
committed
Revert "Fix MeiliSearch analytics tracking (#2888)"
This reverts commit 7ada99f.
1 parent 7ada99f commit e455257

File tree

4 files changed

+28
-246
lines changed

4 files changed

+28
-246
lines changed

api/indexes/strapi-docs/search.js

Lines changed: 0 additions & 53 deletions
This file was deleted.

docusaurus/docs/cms/usage-information.md

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ However, these above actions alone are often insufficient to maintain an overall
2727

2828
Without these metrics, we wouldn't be able to make the right choices as we continue to move forward with the roadmap and provide what you, the community and users, are asking for.
2929

30-
## Collected Strapi-related data
30+
## Collected data
3131

3232
The following data is collected:
3333

@@ -82,22 +82,3 @@ Data collection can later be re-enabled by deleting the flag or setting it to fa
8282
:::note
8383
If you have any questions or concerns regarding data collection, please contact us at the following email address [privacy@strapi.io](mailto:privacy@strapi.io).
8484
:::
85-
86-
## Collected search-related data for docs.strapi.io
87-
88-
To improve our documentation, the public website at `docs.strapi.io` collects anonymous search usage metrics using Meilisearch Cloud. These metrics help us understand how the search performs and where we can make it better:
89-
90-
- Total searches
91-
- Total users (estimated)
92-
- Most searched keywords
93-
- Searches without results
94-
95-
To make the “Total users” metric more accurate while preserving privacy, the site creates a pseudonymous identifier in the browser’s localStorage under the `msUserId` key. It is randomly generated, contains no personal data, rotates on the first visit of each calendar month (UTC), and is sent only with documentation search requests as the `X-MS-USER-ID` header. It is not used for any other purpose.
96-
97-
We do not send click-through or conversion events to Meilisearch.
98-
99-
### Opt-out
100-
101-
If your browser’s Do Not Track setting is enabled, the site does not create or send this identifier.
102-
103-
If this identifier is created, you can remove it at any time by clearing the `msUserId` entry from your browser’s localStorage for docs.strapi.io.

docusaurus/sidebars.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,6 @@ const sidebars = {
363363
type: 'doc',
364364
id: 'cms/customization', // TODO: rename to Introduction
365365
label: 'Introduction',
366-
// key: 'cms-customization-introduction',
367366
},
368367
'cms/configurations/functions',
369368
{
@@ -377,7 +376,6 @@ const sidebars = {
377376
type: 'doc',
378377
id: 'cms/backend-customization',
379378
label: 'Overview',
380-
// key: 'cms-backend-customization-overview',
381379
},
382380
'cms/backend-customization/requests-responses',
383381
'cms/backend-customization/routes',
@@ -417,7 +415,6 @@ const sidebars = {
417415
type: 'doc',
418416
id: 'cms/admin-panel-customization',
419417
label: 'Overview',
420-
// key: 'cms-admin-panel-customization-overview',
421418
},
422419
'cms/admin-panel-customization/logos',
423420
'cms/admin-panel-customization/favicon',
@@ -460,7 +457,6 @@ const sidebars = {
460457
type: 'doc',
461458
id: 'cms/typescript',
462459
label: 'Introduction',
463-
// key: 'cms-typescript-introduction',
464460
},
465461
{
466462
type: 'doc',

docusaurus/src/theme/SearchBar/index.js

Lines changed: 27 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -10,56 +10,11 @@ function SearchBarContent() {
1010
const dropdownRef = useRef(null);
1111
const searchInstanceRef = useRef(null);
1212
const [isLoaded, setIsLoaded] = useState(false);
13-
const originalFetchRef = useRef(null);
14-
15-
function isDoNotTrackEnabled() {
16-
try {
17-
const dnt = (navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack || '').toString();
18-
return dnt === '1' || dnt.toLowerCase() === 'yes';
19-
} catch (_) {
20-
return false;
21-
}
22-
}
23-
24-
function getOrCreateMonthlyUserId() {
25-
if (isDoNotTrackEnabled()) return null;
26-
try {
27-
const key = 'msUserId';
28-
const now = new Date();
29-
const monthKey = now.toISOString().slice(0, 7); // YYYY-MM (UTC)
30-
const raw = window.localStorage.getItem(key);
31-
if (raw) {
32-
try {
33-
const parsed = JSON.parse(raw);
34-
if (parsed && parsed.id && parsed.month === monthKey) {
35-
return parsed.id;
36-
}
37-
} catch {}
38-
}
39-
const uuid = (typeof crypto !== 'undefined' && crypto.randomUUID) ? crypto.randomUUID() : Math.random().toString(36).slice(2) + Date.now().toString(36);
40-
const value = JSON.stringify({ id: uuid, month: monthKey });
41-
window.localStorage.setItem(key, value);
42-
return uuid;
43-
} catch (_) {
44-
return null;
45-
}
46-
}
47-
48-
function shouldAttachUserIdHeader(urlStr) {
49-
try {
50-
const meiliHost = siteConfig?.customFields?.meilisearch?.host;
51-
if (!meiliHost) return false;
52-
const u = new URL(urlStr, window.location.origin);
53-
const meili = new URL(meiliHost);
54-
if (u.origin !== meili.origin) return false;
55-
// Only for search requests
56-
return /\/indexes\/[^/]+\/search$/.test(u.pathname);
57-
} catch {
58-
return false;
59-
}
60-
}
6113

6214
useEffect(() => {
15+
if (!searchButtonRef.current) {
16+
return;
17+
}
6318

6419
const handleKeyDown = (e) => {
6520
const kapaContainer = document.getElementById('kapa-widget-container');
@@ -85,86 +40,22 @@ function SearchBarContent() {
8540

8641
document.addEventListener('keydown', handleKeyDown, true);
8742

88-
// Prepare pseudonymous monthly user id (respects DNT)
89-
const userId = getOrCreateMonthlyUserId();
90-
91-
// Scoped fetch interceptor to add X-MS-USER-ID for Meilisearch search requests
92-
if (typeof window !== 'undefined' && window.fetch && !originalFetchRef.current) {
93-
originalFetchRef.current = window.fetch.bind(window);
94-
window.fetch = async (input, init) => {
95-
try {
96-
const url = typeof input === 'string' ? input : (input && input.url) ? input.url : '';
97-
if (!userId || !shouldAttachUserIdHeader(url)) {
98-
return originalFetchRef.current(input, init);
99-
}
100-
101-
// Attach header depending on input type
102-
if (typeof input === 'string' || input instanceof URL) {
103-
const headers = new Headers(init && init.headers ? init.headers : undefined);
104-
if (!headers.has('X-MS-USER-ID')) headers.set('X-MS-USER-ID', userId);
105-
return originalFetchRef.current(input, { ...(init || {}), headers });
106-
}
107-
108-
// input is Request
109-
const req = input;
110-
const headers = new Headers(req.headers);
111-
if (!headers.has('X-MS-USER-ID')) headers.set('X-MS-USER-ID', userId);
112-
const newReq = new Request(req, { headers });
113-
return originalFetchRef.current(newReq);
114-
} catch (_) {
115-
return originalFetchRef.current(input, init);
116-
}
117-
};
118-
}
119-
120-
// Also patch XMLHttpRequest for libraries that use XHR under the hood
121-
const originalXHROpen = (typeof XMLHttpRequest !== 'undefined' && XMLHttpRequest.prototype.open) ? XMLHttpRequest.prototype.open : null;
122-
const originalXHRSend = (typeof XMLHttpRequest !== 'undefined' && XMLHttpRequest.prototype.send) ? XMLHttpRequest.prototype.send : null;
123-
let xhrPatched = false;
124-
if (originalXHROpen && originalXHRSend) {
125-
try {
126-
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
127-
try { this.__ms_url = url; } catch {}
128-
return originalXHROpen.apply(this, arguments);
129-
};
130-
XMLHttpRequest.prototype.send = function(body) {
131-
try {
132-
if (userId && this && typeof this.setRequestHeader === 'function') {
133-
const url = this.__ms_url || '';
134-
if (shouldAttachUserIdHeader(url)) {
135-
// Only set if not already set
136-
try { this.setRequestHeader('X-MS-USER-ID', userId); } catch {}
137-
}
138-
}
139-
} catch {}
140-
return originalXHRSend.apply(this, arguments);
141-
};
142-
xhrPatched = true;
143-
} catch {}
144-
}
145-
14643
if (searchInstanceRef.current) {
14744
searchInstanceRef.current.destroy?.();
14845
searchInstanceRef.current = null;
14946
}
150-
151-
if (searchButtonRef.current) {
152-
searchButtonRef.current.innerHTML = '';
153-
}
154-
155-
// Initialize docsearch only when container is ready
156-
if (searchButtonRef.current) {
157-
Promise.all([
158-
import('meilisearch-docsearch'),
159-
import('meilisearch-docsearch/css')
160-
]).then(([{ docsearch }]) => {
161-
const baseOptions = {
162-
container: searchButtonRef.current,
163-
// Route through same-origin API to add headers server-side without CORS
164-
host: `${window.location.origin}/api`,
165-
// dummy key for docsearch client; real key sent via header to API
166-
apiKey: 'public',
167-
indexUid: siteConfig.customFields.meilisearch.indexUid,
47+
48+
searchButtonRef.current.innerHTML = '';
49+
50+
Promise.all([
51+
import('meilisearch-docsearch'),
52+
import('meilisearch-docsearch/css')
53+
]).then(([{ docsearch }]) => {
54+
const search = docsearch({
55+
container: searchButtonRef.current,
56+
host: siteConfig.customFields.meilisearch.host,
57+
apiKey: siteConfig.customFields.meilisearch.apiKey,
58+
indexUid: siteConfig.customFields.meilisearch.indexUid,
16859

16960
transformItems: (items) => {
17061
return items.map((item) => {
@@ -244,55 +135,22 @@ function SearchBarContent() {
244135
getMissingResultsUrl: ({ query }) => {
245136
return `https://github.com/strapi/documentation/issues/new?title=Missing+search+results+for+${query}`;
246137
},
247-
};
248-
249-
// Send X-MS-USER-ID to same-origin API; no CORS preflight restrictions
250-
const meiliHost = siteConfig.customFields.meilisearch.host;
251-
const meiliKey = siteConfig.customFields.meilisearch.apiKey;
252-
baseOptions.requestConfig = {
253-
...(baseOptions.requestConfig || {}),
254-
headers: {
255-
...(userId ? { 'X-MS-USER-ID': userId } : {}),
256-
...(meiliHost ? { 'X-Meili-Host': meiliHost } : {}),
257-
...(meiliKey ? { 'X-Meili-Api-Key': meiliKey } : {}),
258-
},
259-
};
260-
baseOptions.headers = {
261-
...(baseOptions.headers || {}),
262-
...(userId ? { 'X-MS-USER-ID': userId } : {}),
263-
...(meiliHost ? { 'X-Meili-Host': meiliHost } : {}),
264-
...(meiliKey ? { 'X-Meili-Api-Key': meiliKey } : {}),
265-
};
266-
267-
const search = docsearch(baseOptions);
138+
});
268139

269-
searchInstanceRef.current = search;
270-
setIsLoaded(true);
140+
searchInstanceRef.current = search;
141+
setIsLoaded(true);
271142

272-
if (colorMode === 'dark') {
273-
dropdownRef.current?.classList.add('dark');
274-
} else {
275-
dropdownRef.current?.classList.remove('dark');
276-
}
277-
}).catch((error) => {
278-
console.error('Failed to load MeiliSearch:', error);
279-
});
280-
}
143+
if (colorMode === 'dark') {
144+
dropdownRef.current?.classList.add('dark');
145+
} else {
146+
dropdownRef.current?.classList.remove('dark');
147+
}
148+
}).catch((error) => {
149+
console.error('Failed to load MeiliSearch:', error);
150+
});
281151

282152
return () => {
283153
document.removeEventListener('keydown', handleKeyDown, true);
284-
if (originalFetchRef.current) {
285-
try {
286-
window.fetch = originalFetchRef.current;
287-
} catch {}
288-
originalFetchRef.current = null;
289-
}
290-
if (xhrPatched && originalXHROpen && originalXHRSend) {
291-
try {
292-
XMLHttpRequest.prototype.open = originalXHROpen;
293-
XMLHttpRequest.prototype.send = originalXHRSend;
294-
} catch {}
295-
}
296154
if (searchInstanceRef.current) {
297155
searchInstanceRef.current.destroy?.();
298156
searchInstanceRef.current = null;
@@ -313,4 +171,4 @@ export default function SearchBar() {
313171
{() => <SearchBarContent />}
314172
</BrowserOnly>
315173
);
316-
}
174+
}

0 commit comments

Comments
 (0)