[CDX-470] Add additionalTrackingKeys option#472
Conversation
…vents Adds a new `additionalTrackingKeys` client option that duplicates tracking events to additional API keys. When configured, each tracking event queued via RequestQueue is also sent to each additional key with the `key` parameter swapped in both the URL and POST body.
There was a problem hiding this comment.
Pull request overview
Adds an additionalTrackingKeys client option to support duplicating tracking events across multiple Constructor.io API keys, primarily by cloning queued RequestQueue entries with the key swapped in the URL/body.
Changes:
- Introduces
additionalTrackingKeys?: string[]onConstructorClientOptionsand wires it throughConstructorIOoptions. - Updates
RequestQueueto enqueue duplicate tracking requests per additional key. - Adds unit + integration tests validating duplication behavior and invalid-key filtering.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/request-queue.js | Duplicates queued tracking requests for each configured additional key |
| src/types/index.d.ts | Adds additionalTrackingKeys?: string[] to the public options type |
| src/constructorio.js | Plumbs additionalTrackingKeys through normalized client options |
| spec/src/utils/request-queue.js | Unit tests for duplication, empty/missing option, invalid entries, GET behavior |
| spec/src/modules/tracker.js | Integration test asserting fetch is called for both primary + additional keys |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
esezen
left a comment
There was a problem hiding this comment.
Thanks! This is looking great. I left some comments
- Use Set to remove duplicate additionalTrackingKeys and exclude the primary apiKey - Assert duplicate request URL does not contain the original key - Add test verifying request bodies are identical except for the key field - Improve JSDoc description for additionalTrackingKeys parameter Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-client-js Resolve conflicts: keep both useWindowParameters (from master) and additionalTrackingKeys (from this branch) in constructorio.js and index.d.ts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This PR adds an additionalTrackingKeys option that duplicates every tracking event to one or more additional API keys — the implementation is compact and the tests are thorough. A few correctness and reliability issues need to be addressed before merging.
Inline comments: 6 discussions added
Overall Assessment:
| expect(queue[2].url).to.contain('key=another-valid-key'); | ||
| }); | ||
|
|
||
| it('Should not duplicate events when additionalTrackingKeys contains the primary key or duplicates', () => { |
There was a problem hiding this comment.
Suggestion: This test is a good addition. However, the test verifies that queue.length === 2 (primary + one unique extra), which is correct. Consider also asserting that neither queue[0] nor queue[1] contains a duplicate of the primary key in both the URL and the body to make the intent of the deduplication explicit:
expect(queue[0].body.key).to.equal('primary-key');
expect(queue[1].body.key).to.equal('extra-key');This guards against the body not being swapped even when the URL deduplication works correctly.
| additionalTrackingKeys: ['extra-key-1', 'extra-key-2'], | ||
| }); | ||
|
|
||
| expect(instance.options).to.have.property('additionalTrackingKeys').to.deep.equal(['extra-key-1', 'extra-key-2']); |
There was a problem hiding this comment.
Suggestion: The setClientOptions test for additionalTrackingKeys only covers the DOM-less path. Given that the existing tests for other options (e.g. apiKey, segments) include a parallel test that asserts the change propagates to sub-module options (instance.tracker.options, instance.search.options, etc.), consider adding the same assertion here — or, at minimum, asserting instance.tracker.requests.options.additionalTrackingKeys if direct access is available. This ensures the shared-reference contract (noted above in the constructorio.js comment) is actually tested.
There was a problem hiding this comment.
Claude raised a good point. We should have equivalent tests for the DOM context.
jjl014
left a comment
There was a problem hiding this comment.
Looking pretty solid to me. I did leave a couple comments that I'd like to get your thoughts on. Thanks!
| const encodedOriginalKey = helpers.encodeURIComponentRFC3986(this.options.apiKey); | ||
|
|
||
| const uniqueKeys = new Set( | ||
| additionalKeys.filter((key) => key && typeof key === 'string' && key !== this.options.apiKey), | ||
| ); | ||
|
|
||
| uniqueKeys.forEach((additionalKey) => { | ||
| const encodedAdditionalKey = helpers.encodeURIComponentRFC3986(additionalKey); | ||
| const swappedUrl = url.replace(`key=${encodedOriginalKey}`, `key=${encodedAdditionalKey}`); |
There was a problem hiding this comment.
Any reason why we're doing this validation and uniqueness check every time we queue an event?
It feels like an additional step that could be handled earlier (e.g. during client instantiation in the construtor or when setClientOptions is called)?
| additionalTrackingKeys: ['extra-key-1', 'extra-key-2'], | ||
| }); | ||
|
|
||
| expect(instance.options).to.have.property('additionalTrackingKeys').to.deep.equal(['extra-key-1', 'extra-key-2']); |
There was a problem hiding this comment.
Claude raised a good point. We should have equivalent tests for the DOM context.
| this.options.serviceUrl = formattedServiceUrl || this.options.serviceUrl; | ||
| } | ||
|
|
||
| if (Array.isArray(additionalTrackingKeys)) { |
There was a problem hiding this comment.
Not a big deal, but if we wanted to stop sending events to multiple keys, we would have to send [] at the moment. Should also support null here?
Summary
additionalTrackingKeysoption toConstructorClientOptionsthat accepts an array of API key stringsRequestQueueis duplicated for each additional key, with thekeyswapped in both the URL query string and POST bodyUsage
Changes
src/types/index.d.ts— AddedadditionalTrackingKeys?: string[]to options interfacesrc/constructorio.js— Pass through the new optionsrc/utils/request-queue.js— Duplicate queued requests for each additional keyspec/src/utils/request-queue.js— Unit tests (5 cases)spec/src/modules/tracker.js— Integration testTest plan
Resolves CDX-470