Skip to content

Commit 5e5b811

Browse files
authored
fixed clickthrough handling for duplicate s_kwcid/ef_id query params (#1443)
* test: add duplicate s_kwcid regression coverage * fix: normalize duplicate s_kwcid values * fix: remove redundant code * chore: add changeset
1 parent 1c53385 commit 5e5b811

File tree

4 files changed

+99
-8
lines changed

4 files changed

+99
-8
lines changed

.changeset/shaky-lines-flash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@adobe/alloy": patch
3+
---
4+
5+
Fixed an issue where there are multiple s_kwcid or ef_id parameters in url"

packages/core/src/components/Advertising/handlers/clickThroughHandler.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import {
2828
* @param {Object} params.cookieManager - Session manager for cookie operations
2929
* @param {Object} params.adConversionHandler - Handler for sending ad conversion events
3030
* @param {Object} params.logger - Logger instance
31-
* @param {string} params.skwcid - Search keyword click ID
32-
* @param {string} params.efid - EF ID parameter
31+
* @param {string | string[]} params.skwcid - Search keyword click ID
32+
* @param {string | string[]} params.efid - EF ID parameter
3333
* @param {Object} params.optionsFromCommand - Additional options from command
3434
* @returns {Promise} Result of the ad conversion tracking
3535
*/
@@ -38,10 +38,13 @@ export default async function handleClickThrough({
3838
cookieManager,
3939
adConversionHandler,
4040
logger,
41-
skwcid,
42-
efid,
41+
skwcid: rawSkwcid,
42+
efid: rawEfId,
4343
}) {
44-
logger.info(LOG_AD_CONVERSION_START, { skwcid, efid });
44+
const skwcid = Array.isArray(rawSkwcid) ? rawSkwcid[0] : rawSkwcid;
45+
const efid = Array.isArray(rawEfId) ? rawEfId[0] : rawEfId;
46+
47+
logger.info(LOG_AD_CONVERSION_START, { skwcid: skwcid, efid });
4548

4649
const event = eventManager.createEvent();
4750
if (
@@ -51,8 +54,8 @@ export default async function handleClickThrough({
5154
) {
5255
const clickData = {
5356
click_time: Date.now(),
54-
...(typeof skwcid !== "undefined" && { skwcid }),
55-
...(typeof efid !== "undefined" && { efid }),
57+
skwcid,
58+
efid,
5659
};
5760
cookieManager.setValue(LAST_CLICK_COOKIE_KEY, clickData);
5861
}
@@ -61,7 +64,9 @@ export default async function handleClickThrough({
6164
_experience: {
6265
adcloud: {
6366
conversionDetails: {
64-
...(typeof skwcid !== "undefined" && { [TRACKING_CODE]: skwcid }),
67+
...(typeof skwcid !== "undefined" && {
68+
[TRACKING_CODE]: skwcid,
69+
}),
6570
...(typeof efid !== "undefined" && {
6671
[TRACKING_IDENTITIES]: efid,
6772
}),
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
Copyright 2025 Adobe. All rights reserved.
3+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
*/
5+
6+
import { test, describe, expect } from "../../helpers/testsSetup/extend.js";
7+
import { sendEventHandler } from "../../helpers/mswjs/handlers.js";
8+
import alloyConfig from "../../helpers/alloy/config.js";
9+
import {
10+
createAdvertisingConfig,
11+
findClickThroughCall,
12+
validateClickThroughCall,
13+
} from "../../helpers/advertising.js";
14+
15+
describe("Advertising - Clickthrough (duplicate s_kwcid)", () => {
16+
test("should use the first s_kwcid value when duplicates are present", async ({
17+
alloy,
18+
worker,
19+
networkRecorder,
20+
}) => {
21+
worker.use(...[sendEventHandler]);
22+
23+
const url = new URL(window.location.origin + window.location.pathname);
24+
url.searchParams.append("s_kwcid", "AL!first-keyword");
25+
url.searchParams.append("s_kwcid", "AL!second-keyword");
26+
url.searchParams.set("ef_id", "test_experiment_456");
27+
window.history.replaceState({}, "", url.toString());
28+
29+
await alloy("configure", {
30+
...alloyConfig,
31+
...createAdvertisingConfig(),
32+
});
33+
34+
await alloy("sendEvent");
35+
36+
const calls = await networkRecorder.findCalls(/edge\.adobedc\.net/);
37+
const conversionCall = findClickThroughCall(calls);
38+
expect(conversionCall).toBeTruthy();
39+
validateClickThroughCall(conversionCall, {
40+
sampleGroupId: "AL!first-keyword",
41+
experimentId: "test_experiment_456",
42+
});
43+
});
44+
});

packages/core/test/unit/specs/components/Advertising/handlers/clickThroughHandler.spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,4 +332,41 @@ describe("Advertising::clickThroughHandler", () => {
332332

333333
expect(logger.error).toHaveBeenCalled();
334334
});
335+
336+
it("should handle duplicate s_kwcid values by using the first value", async () => {
337+
const mockEvent = {
338+
setUserXdm: vi.fn(),
339+
finalize: vi.fn(),
340+
};
341+
eventManager.createEvent.mockReturnValue(mockEvent);
342+
343+
const result = await handleClickThrough({
344+
eventManager,
345+
cookieManager,
346+
adConversionHandler,
347+
logger,
348+
skwcid: ["AL!first-value", "AL!second-value"],
349+
efid: "test-efid",
350+
optionsFromCommand: {},
351+
});
352+
353+
expect(mockEvent.setUserXdm).toHaveBeenCalledWith(
354+
expect.objectContaining({
355+
_experience: {
356+
adcloud: {
357+
conversionDetails: {
358+
trackingCode: "AL!first-value",
359+
trackingIdentities: "test-efid",
360+
},
361+
},
362+
},
363+
}),
364+
);
365+
expect(cookieManager.setValue).toHaveBeenCalledWith(LAST_CLICK_COOKIE_KEY, {
366+
click_time: expect.anything(),
367+
skwcid: "AL!first-value",
368+
efid: "test-efid",
369+
});
370+
expect(result).toEqual({ status: "success" });
371+
});
335372
});

0 commit comments

Comments
 (0)