Skip to content

Conversation

@ssilare-adobe
Copy link
Contributor

SITES-36715

Add CPC Calculation Utility

Summary

Adds a new utility function to calculate Cost Per Click (CPC) values from Ahrefs organic traffic data stored in S3.

Changes

  • Added calculateCPCValue function in metrics-store.js

    • Fetches organic traffic data from S3 for a given site
    • Calculates CPC value based on cost and traffic metrics
    • Returns default value (1.5) when data is unavailable or invalid
    • Full error handling and validation
  • Added getObjectFromKey helper in s3.js

    • Generic utility to retrieve and parse objects from S3
    • Handles JSON parsing with fallback to raw content
    • Graceful error handling for missing objects
  • Added DEFAULT_CPC_VALUE constant (1.5)

  • Updated exports in index.js and index.d.ts

Please ensure your pull request adheres to the following guidelines:

  • make sure to link the related issues in this description
  • when merging / squashing, make sure the fixed issue references are visible in the commits, for easy compilation of release notes

Related Issues

Thanks for contributing!

@ssilare-adobe ssilare-adobe requested a review from a team October 28, 2025 04:17
@github-actions
Copy link

This PR will trigger a minor release when merged.

return DEFAULT_CPC_VALUE;
}
const lastTraffic = organicTrafficData.at(-1);
if (!lastTraffic.cost || !lastTraffic.value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current validation catches 0 and falsy values but misses:
Negative numbers: cost: -100 or value: -50 would pass validation but produce incorrect CPC calculations
Non-numeric types: value: "hello" or value: NaN would pass through and result in NaN on line 121

Can do something like this
// Validate both values are positive numbers
if (typeof lastTraffic.cost !== 'number' ||
typeof lastTraffic.value !== 'number' ||
!Number.isFinite(lastTraffic.cost) ||
!Number.isFinite(lastTraffic.value) ||
lastTraffic.cost <= 0 ||
lastTraffic.value <= 0) {
log.warn(Invalid organic traffic data for ${siteId} - cost:${lastTraffic.cost} value:${lastTraffic.value}. Using Default CPC value.);
return DEFAULT_CPC_VALUE;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add null check aswell

}
}
// Always return body for non-JSON content types
return body;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent return types,
Can we make it to string always or json always.

const organicTrafficData = await getObjectFromKey(s3Client, bucketName, key, log);
if (!Array.isArray(organicTrafficData) || organicTrafficData.length === 0) {
log.warn(`Organic traffic data not available for ${siteId}. Using Default CPC value.`);
return DEFAULT_CPC_VALUE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead setting default and return
how about we let downstream decide default.

As there will be no identifier if cpc is 1.5 its because of default or its actual.

Like upstream should get something which shows we are unable to fetch with reason

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants