> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kameleoon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Revenue goal

> Set up accurate revenue goal tracking in Kameleoon using tag managers, global scripts, or SDKs, with guidance on currency, format, and deduplication.

Setting up a revenue goal in Kameleoon is straightforward, but it requires careful configuration to ensure everything works correctly. Every website has its own structure, purchase flow, tracking setup, and edge cases, so there's no one-size-fits-all solution. Without proper configuration, you risk missing key data points, double-counting transactions, or misinterpreting performance.

The recommendations below cover the most common challenges Kameleoon users encounter and offer flexible solutions you can adapt to your setup.

## Implementation method

Kameleoon supports multiple integration methods to track revenue goals effectively, depending on your experimentation type and technical setup. The sections below cover the recommended approaches for both Web Experimentation (WE) and Feature Experimentation (FE), including support for offline conversions via the Kameleoon Data API.

### Web Experimentation

* **Using a tag manager:** Implement the [`kameleoonQueue`](../../../developer-docs/apis/activation-api-js/api-reference/command-queue#syntax), which ensures that conversion events trigger in sync with your analytics platform, maintaining data consistency across tools and improving your site's performance. For a detailed implementation guide in Google Tag Manager, refer to [this comprehensive guide](../../integrations/as-a-destination/analytics/google-analytics-4/google-tag-manager) and the configuration steps below to set up the revenue goal.
* **[Using the global custom script:](../../project-management/manage-your-projects#global-script)** If `kameleoonQueue` isn't compatible with your setup, you can manually implement the revenue goal using the Activation API within the global custom script in the Kameleoon app.

### Feature Experimentation

If you're using one of [Kameleoon's SDKs](../../../developer-docs/feature-experimentation/get-started/overview), you can track revenue goals using the [`trackConversion()`](../../../developer-docs/sdks/web-sdks/nodejs-sdk#trackconversion) method. Refer to the steps below to properly configure the revenue goal based on your SDK environment.

### Data API

*(Applicable for both WE and FE)*

For offline conversions, such as purchases completed over the phone or in-store, you can use the [Kameleoon Data API](../../../developer-docs/apis/data-api-rest/tutorials/processing-offline-goal-conversions-in-experiments#sending-offline-goal-conversion) to process offline goal conversions. This method is best when the conversion event occurs outside the user's online journey but still must be tracked and attributed within your Kameleoon experiments.

## Configuration

### Scope

Before setting up your revenue goal, check whether the transaction confirmation always occurs on a single, consistent page. In some setups—especially those involving mobile apps, embedded checkouts, or third-party payment providers—the confirmation might appear in a web view or on a separate domain. Install Kameleoon on **all** relevant pages or views where confirmation may appear. This ensures Kameleoon reliably tracks conversions and captures all revenue data. If a user can complete a transaction across multiple URLs (due to variations in query parameters or different payment flows, for example), add **all relevant URLs** in Kameleoon's settings so that no conversions are missed.

### Transaction goal (access the confirmation page)

Set a goal for accessing the confirmation page without a revenue amount. This goal helps you identify missing conversions for the revenue goal—delays in loading the revenue amount on the page (in the DOM, `dataLayer`, or a similar object) are a common cause of missed conversions. To set up a transaction goal in WE, choose between two goal types:

* **Access to a page:** Set the URL in the goal's configuration. Depending on the URL's structure, use either **URL contains** or **Matches the regular expression** to account for variations in the URL (different paths or query parameters, for example). Avoid **Corresponds exactly to**, as the URL will likely include parameters that vary.

<Note>
  When using the **Access to a page** goal type, if visitors can reload the confirmation page without being redirected (to the homepage, for example), the goal may trigger again. In this case, use the **converted visits** metric rather than **all conversions** on the Results page to avoid overcounting.
</Note>

* **Custom goal:** This goal type prevents the goal from converting again if the confirmation page reloads. Implement a custom goal in the global custom script and use a `sessionStorage` check to prevent duplicate conversions (see the example code below). This approach is recommended because you can reuse the same code to trigger the revenue goal, which improves performance by eliminating the need for a native **Access to a page** goal.

```javascript theme={null}
if (
   document.location.href.includes("/confirmation/") &&
   !window.sessionStorage.getItem("kameleoonGoalConverted")
 ) {
   // Set an item in sessionStorage to prevent a second conversion if the page is reloaded
   window.sessionStorage.setItem("kameleoonGoalConverted", "true");
   // Convert the transaction goal, replace the ID below
   Kameleoon.API.Goals.processConversion(355733);
 } else if (!document.location.href.includes("confirmation")) {
   // Remove the item from sessionStorage to allow conversion for a new transaction
   window.sessionStorage.removeItem("kameleoonGoalConverted");
 }
```

### Revenue format

Ensure the revenue amount is properly formatted and validated before processing:

* Replace commas (`,`) with periods (`.`) for decimal consistency.
* Remove any spaces (can be present in amounts over 1,000).
* Strip out currency symbols (such as `$`).
* Convert the cleaned string into a numeric data type for accurate calculations.

For example:

```javascript theme={null}
let revenue = parseFloat(revenue.replace(",", ".").replace(/[^0-9.]/g, "").replace(/\s+/g, ""));
```

### Currencies

A website may support multiple currencies. Compare conversion values expressed in the same currency to avoid misleading results or incorrect analyses. Verify that the currency used in your tracking and reporting is consistent across all conversions.

You can trigger a goal for each currency and/or use Kameleoon's conversion web service. The endpoint is provided below—ensure all arguments passed are valid.

```
<https://customers.kameleoon.com/kameleoon/currencies/convert?inputCurr=${inputCurr}&outputCurr=${outputCurr}&amount=${revenue}>;
```

<Warning>
  Never convert the same goal using amounts in different currencies. You must either create a separate goal for each currency, or unify them by setting up a global goal using the web service endpoint above. This service converts all amounts into a single currency of your choice.
</Warning>

See the complete code example at the end of this article for a detailed implementation of the currency conversion web service.

### Order ID

Add a [custom data](../custom-data/create-custom-data) to store the order ID and use it as [metadata](./create-a-goal#metadata) for the revenue goal. This links each conversion to the order ID, making it easier to match transactions with your analytics tool and investigate data discrepancies.

Configure the custom data using the screenshot below as a reference. Adjust the format depending on whether the order ID on your site is a number or a string.

<Frame style={{width: '60%', margin: '0 auto'}}>
  <img src="https://storage.googleapis.com/kameleoon-storage-documentation/user-manual/images/assets/goals/revenue-goal/new-custom-data.png" alt="New custom data configuration for Order ID" style={{width: "100%"}} />
</Frame>

To associate the **OrderID** custom data with your revenue goal:

1. In the goal creation flow, enter your goal's information and select **Custom goal** as the goal type.
2. Click **Next** > **Advanced settings**.
3. Toggle **Collect metadata, associating goals to custom data**.
4. Select **OrderID** from the dropdown.

<Frame style={{width: '60%', margin: '0 auto'}}>
  <img src="https://storage.googleapis.com/kameleoon-storage-documentation/user-manual/images/assets/goals/revenue-goal/associate-custom-data.png" alt="Associating OrderID custom data with the revenue goal" style={{width: "100%"}} />
</Frame>

See the complete code sample below for how to set the custom data value.

## Complete example

*This example is for WE and can be used as a reference for implementation in FE.*

Now that you've reviewed each key element—scope, transaction logic, revenue format, currency handling, and order ID tracking—you're ready to bring everything together.

Below is a complete example of how to implement the revenue goal using the global custom script in Kameleoon.

```javascript theme={null}
 // Amount conversion using Kameleoon's currency conversion web service
 const convertCurrency = async (revenue, inputCurr, outputCurr) => {
     if (revenue == 0) return 0;
     const response = await fetch(
         `https://customers.kameleoon.com/kameleoon/currencies/convert?inputCurr=${inputCurr}&outputCurr=${outputCurr}&amount=${revenue}`,
         {
             method: 'GET',
             headers: {
                 'Content-Type': 'text/plain',
             },
         }
     );
     return response.json();
 };
 

 // Logic to:
 // - Convert the transaction goal 
 // - Convert a goal for each currency
 // - Convert the global revenue goal
 // - Set the orderID custom data
 // repalce all goal IDs in the code
 if (document.location.href.includes("/confirmation/") && !window.sessionStorage.getItem("kameleoonGoalConverted")) {
     Kameleoon.API.Goals.processConversion(355733); // Transaction goal
     sessionStorage.setItem("kameleoonGoalConverted", "true");
 

     let revenueLayer;
     Kameleoon.API.Core.runWhenConditionTrue(() => {
         revenueLayer = window.dataLayer?.find(layer => layer.ecommerce?.purchase?.actionField?.revenue);
         return revenueLayer;
     }, () => {
         let revenue = parseFloat(revenueLayer.ecommerce.purchase.actionField.revenue);
         const inputCurr = revenueLayer.ecommerce.purchase.actionField.inputCurrency;
         const orderID = revenueLayer.ecommerce.purchase.actionField.orderID;
 

         if (!isNaN(revenue)) {
             revenue = revenue.toString().replace(",", ".").replace(/[^0-9.]/g, "").replace(/\s+/g, "");
             // Currency-specific revenue goals
             switch (inputCurr) {
                 case 'GBP':
                     Kameleoon.API.Goals.processConversion(355641, revenue);
                     break;
                 case 'USD':
                     Kameleoon.API.Goals.processConversion(355643, revenue);
                     break;
                 case 'EUR':
                     Kameleoon.API.Goals.processConversion(355642, revenue);
                     break;
                 default:
                     Kameleoon.API.Goals.processConversion(355649); // Other currencies (no revenue passed)
             }
             // Global revenue goal in output currency (you can use ISO 4217 codes for each country)
             const outputCurr = "USD";
             convertCurrency(revenue, inputCurr, outputCurr).then((convertedRevenue) => {
                 // The custom data must be set before the goal is converted
                 Kameleoon.API.Data.setCustomData("orderID", orderID);
                 Kameleoon.API.Goals.processConversion(353518, convertedRevenue);
             }).catch((error) => {
 // Create a Custom Data to store potential errors for debugging
                 Kameleoon.API.Data.setCustomData("[KAM] - currency webservice error", `error: ${error.toString()}; revenue: ${revenue}; inputCurr ${inputCurr}; outputCurr ${outputCurr}`);
                 console.error("Error in currency conversion:", error);
             });
         }
     });
 } else if (!document.location.href.includes("/confirmation/")) {
     sessionStorage.removeItem("kameleoonGoalConverted");
 } 
```

Below is a screenshot of the `dataLayer` structure on the confirmation page for reference.

<Frame>
  ![](https://storage.googleapis.com/kameleoon-storage-documentation/user-manual/images/assets/goals/revenue-goal/image-43-1-1536x631.png)
</Frame>

Setting up a reliable revenue goal in Kameleoon requires careful alignment with your site's structure, `dataLayer` setup, and currency formats. By following the guidelines above, whether through a tag manager or global custom script, you can ensure accurate tracking, reduce discrepancies with your analytics tools, and gain more meaningful insights from your experiments. Test thoroughly and validate your implementation to maintain data integrity.
