# Integrate Google Cloud CDN with Fraud Prevention JavaScript SDK

[Google Cloud CDN](https://cloud.google.com/cdn/docs/overview) is a fully managed service that distributes HTTP(S) traffic across backend services and can inspect and modify traffic at the edge. This allows it to act not only as a global entry point for applications but also as a point of control for injecting or filtering content in transit.

Mosaic provides a native integration with GCP **Service Extensions** that enables you to inject the **Device Risk & Security (Fraud Prevention) JavaScript SDK** into HTML responses automatically, without modifying your web application code.

This plugin intercepts HTML responses at the CDN level and injects the required `<script>` tags for the Fraud Prevention SDK. As a result, every page served through the CDN includes the Fraud Prevention SDK, allowing Mosaic to capture risk signals from client devices transparently.

## How it works

When a client requests an HTML page, the request passes through the **GCP CDN** (1).
The backend returns the response, which is intercepted by the **Fraud Prevention plugin** (2) at the CDN and modified to inject the SDK before being delivered to the browser. Once the page is loaded, the browser executes the injected Fraud Prevention SDK (formerly DRS) (3). The SDK collects device and risk signals client-side and forwards them to Mosaic for analysis (4).

The plugin uses the following **injection strategy** (fallback order):

- After `<meta charset>` (preferred)
- After `<head>`
- Before `<body>`
- At the beginning of the document



```mermaid
sequenceDiagram
    participant U as Client
    participant LB as GCP CDN
    participant BE as Backend
    participant SE as Service Ext (FP WASM Plugin)
    participant Fraud Prevention as FP SDK

    U->>LB: HTTP GET /page.html

    Note over LB: Step 1

    LB->>BE: Forward request
    BE-->>LB: HTML response

    Note over LB, SE: Step 2

    LB->>SE: RESPONSE_HEADERS/BODY event (intercept)
    SE-->>SE: Inject script for Fraud Prevention SDK and init block
    SE-->>LB: Modified HTML response
    LB-->>U: Deliver modified HTML

    Note over U: Step 3

    U->>Fraud Prevention: Browser loads injected Fraud Prevention script

    Note over Fraud Prevention: Step 4

    Fraud Prevention-->>Fraud Prevention: Initialize with clientId + serverPath
    Fraud Prevention-->>Mosaic: Send device/risk signals
```

## Before you start

Before you begin:

- A Google Cloud Platform account with billing enabled.
- A **Global External HTTPS CDN** (only HTTPS is supported).
- `gcloud` CLI installed and configured (version **534.0.0** or higher).


## Step 1: Get client credentials

div
div
Admin Portal
Client credentials are used to identify your app and generate access tokens for authorizing Mosaic requests. To obtain them, you'll need to create an application in the [Admin Portal](https://portal.transmitsecurity.io/) (if you don’t have one yet).

1. From **Applications**, click **Add application**.
2. Add the friendly application name to display in the Admin Portal.
3. Add a client display name, and your website URL as a redirect URI (e.g., `https://your-domain.com`). These fields are required for all Mosaic apps, but won’t be used for Fraud Prevention.
4. Click **Add** to create your application. This will automatically generate your client credentials (you'll need your client ID in [step 3](#step-3-deploy-the-html-injection-wasm-plugin)).


## Step 2: Set up your  Google Cloud environment

div
div
GCP
Before deploying the plugin, you need to prepare your Google Cloud environment.
Define your project and enable the required API for Service Extensions.

Run the following commands from a terminal where the **gcloud CLI** is installed and authenticated (for example, in your local terminal or in the [Google Cloud Shell](https://cloud.google.com/shell)).
Make sure you have the necessary permissions to run these commands; if not, contact your GCP administrator.


```bash
# Set your GCP project ID
gcloud config set project YOUR_PROJECT_ID

# Enable the Service Extensions API (required for deploying the plugin)
gcloud services enable serviceextensions.googleapis.com
```

## Step 3: Deploy the HTML Injection WASM plugin

div
div
GCP
In this step you deploy the **Fraud Prevention HTML Injection WASM plugin** provided by Mosaic.
This plugin runs as a GCP Service Extension and is responsible for intercepting HTML responses at the CDN level and injecting the Fraud Prevention SDK automatically, without requiring changes to your application code.

The plugin accepts the following parameters:

| Parameter | Description | Example |
|  --- | --- | --- |
| `clientId` | Your Mosaic app client ID | `XXXXXXXXXXXXXXX_XXX` |
| `serverPath` | Fraud Prevention API server path | `https://api.transmitsecurity.io/risk-collect/` |


Note
Never expose your `clientId` in client-side code samples, public docs, or unsecured environments.

Common server paths by region:

- US: `https://api.transmitsecurity.io/risk-collect/`
- EU: `https://api.eu.transmitsecurity.io/risk-collect/`
- Canada: `https://api.ca.transmitsecurity.io/risk-collect/`
- Australia: `https://api.au.transmitsecurity.io/risk-collect/`



```bash
# Set variables for easy configuration
PLUGIN_VERSION="v1-3"   # replace with the desired version (currently "v1-3")
PLUGIN_IMAGE="us-central1-docker.pkg.dev/dev-riskid/drs-plugins/drs-sdk-plugin-go:latest"  # replace with the image URI (currently Transmit Security's public image)
CLIENT_ID="YOUR_CLIENT_ID"   # replace with your DRS client ID (provided by Transmit Security)
SERVER_PATH="YOUR_SERVER_PATH"   # replace with your DRS server path (see examples below)

# Create plugin configuration file
cat > plugin-config.txt << EOF
clientId=${CLIENT_ID},serverPath=${SERVER_PATH}
EOF

# Create the WASM plugin
gcloud service-extensions wasm-plugins create drs-html-injection-plugin \
    --location=global \
    --main-version="${PLUGIN_VERSION}" \
    --image="${PLUGIN_IMAGE}" \
    --plugin-config-file="plugin-config.txt" \
    --log-config="enable=True,sample-rate=1.0,min-log-level=INFO" \
    --description="DRS HTML Injection Plugin - Automatically injects DRS SDK into HTML responses"

# (Optional)Clean up config file
rm plugin-config.txt
```

You will receive a response similar to the one below:


```curl
Create request issued for: [drs-html-injection-plugin]
Waiting for operation [projects/dev-riskid/locations/global/operations/operation-1755779730683-63cdf5326b4c9-95d21107-9fd2f84e] to complete...done.
Created WasmPlugin [drs-html-injection-plugin] with WasmPluginVersion [PLUGIN_VERSION].
```

### Example of injected code

When the plugin processes an HTML response, it automatically injects into the page a snippet similar to the one below. This happens at the CDN level — you do not need to add this code manually.


```html
<script async src="https://platform-websdk.transmitsecurity.io/platform-websdk/2.x/ts-platform-websdk.js"></script>
<script>
window.addEventListener('load', function() {
  if (window.tsPlatform) {
    window.tsPlatform.initialize({
      clientId: 'YOUR_CLIENT_ID',
      drs: {
        serverPath: 'YOUR_SERVER_PATH'
      }
    });
    console.log('DRS SDK initialized');
  }
});
</script>
```

Note
The values YOUR_CLIENT_ID and YOUR_SERVER_PATH are automatically taken from the plugin configuration.
You do not need to replace them manually in your application code.

Note
Use the [Google Cloud CLI](https://cloud.google.com/sdk/gcloud/reference) to check logs and monitor the status of your Service Extension and CDN.

## Step 4: Configure the GCP CDN

div
div
GCP
**Attach the plugin to your CDN** so it can intercept traffic. This is done by creating a **Service Extension** that links the plugin to the forwarding rule of your HTTPS CDN.

1. Identify the forwarding rule used by your CDN:



```bash
# Set your CDN name (replace with your CDN name)
LOAD_BALANCER_NAME="your-load-balancer-name"

# Get the target HTTPS proxy for your CDN
TARGET_PROXY_NAME=$(gcloud compute target-https-proxies list --filter="urlMap:${LOAD_BALANCER_NAME}" --format="value(name)")

# Find forwarding rules that use this target proxy
# (replace FORWARDING_RULE_NAME with your CDN's forwarding rule name)
gcloud compute forwarding-rules list --global --filter="target:${TARGET_PROXY_NAME}" --format="value(name)"
```

1. Create a Service Extension configuration file that attaches the previously deployed plugin (`drs-html-injection-plugin`) to your forwarding rule:



```yaml
# Set variables for your GCP resources
PROJECT_ID="YOUR_PROJECT_ID"            # replace with your GCP project ID
FORWARDING_RULE_NAME="YOUR_FORWARDING_RULE_NAME"  # replace with your CDN's forwarding rule name

# Create service extension configuration
cat > drs-service-extension.yaml << EOF
name: projects/${PROJECT_ID}/locations/global/lbTrafficExtensions/drs-injection-service
description: "DRS HTML Injection Service Extension"
loadBalancingScheme: EXTERNAL_MANAGED
forwardingRules:
- https://www.googleapis.com/compute/v1/projects/${PROJECT_ID}/global/forwardingRules/${FORWARDING_RULE_NAME}
extensionChains:
- name: drs-injection-chain
  matchCondition:
    celExpression: "true"
  extensions:
  - name: drs-html-injection-plugin
    service: projects/${PROJECT_ID}/locations/global/wasmPlugins/drs-html-injection-plugin
    supportedEvents:
    - RESPONSE_BODY
    - RESPONSE_HEADERS
    failOpen: true
EOF
```

1. Apply the Service Extension so it becomes active on the CDN:



```bash
gcloud service-extensions import drs-service-extension.yaml
```

## Step 5: Set user

div
div
Client
A user identifier must be reported to Mosaic **after the user is fully authenticated** (including any required 2FA). This sets the user for all subsequent events in the current browser session.

The Web SDK is automatically injected and initialized by the CDN plugin after Steps 3–4.
You only need to call `setAuthenticatedUser` once `window.tsPlatform` is available.
Implement this in your **web application code**. The `[USER_ID]` is an opaque identifier for the user in your system.


```js
await window.tsPlatform.drs.setAuthenticatedUser('[USER_ID]');
```

Note
Do not include personal user identifiers (e.g., email) in plain text.

## Step 6: Trigger actions

div
div
Client
To obtain risk recommendations for sensitive actions, your application should **report these actions from the web app** using the [Platform SDK](/sdk-ref/platform/introduction). Add an event listener to the relevant form or button in your page and include the following code **in your web application** (after SDK initialization). Replace `[ACTION_TYPE]` with an action from the [list of actions](/guides/risk/recommendations#action-types). Optionally pass a correlation ID and a claimed user ID (for unauthenticated users).


```js
// Trigger events for the action and get the actionToken
// (Optional) correlationId and claimedUserId help improve Fraud Prevention
const tsAccountProtectionLoginHandler = `
<script>
 async function onSubmitLogin(event) {
   event.preventDefault();
   try {
    const value = await window.tsPlatform.drs.triggerActionEvent("[ACTION_TYPE]", { correlationId: "[CORRELATION_ID]", claimedUserId: "[CLAIMED_USER_ID]" });
    form.submit();
   } catch (error) {
     form.submit();
   };
 }
 let form = document.getElementById("login");
 if (form) {
   form.addEventListener('submit', onSubmitLogin);
 }
</script>
`;
```

Note (Backend handoff)
Make sure to pass the received `actionToken` to your **backend** together with the actual action invocation so that your server can fetch the recommendation in the next step.

## Step 7: Fetch recommendation

div
div
Backend
From your **server**, fetch recommendations for the reported action using the [Recommendation API](/openapi/risk/recommendations.openapi/other/getriskrecommendation).

These APIs are authorized using an OAuth access token. Obtain a token with **client credentials** (from Step 1).


```js
  const { access_token } = await fetch(
    `https://api.transmitsecurity.io/oidc/token`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
      body: new URLSearchParams({
        grant_type: client_credentials,
        client_id: [CLIENT_ID],
        client_secret: [CLIENT_SECRET]
      })
    }
  );
```

From your backend, invoke the Recommendation API. The `[ACCESS_TOKEN]` is the token you obtained above and `[ACTION_TOKEN]` is the `actionToken` received from the SDK in Step 6.


```js
const query = new URLSearchParams({
  action_token: '[ACTION_TOKEN]',
}).toString();

const resp = await fetch(
  `https://api.transmitsecurity.io/risk/v1/recommendation?${query}`,
  {
    method: 'GET',
    headers: {
      Authorization: 'Bearer [ACCESS_TOKEN]',
    },
  }
);
```

Note (Backend step)
This is a **server-side (machine-to-machine)** call and is not handled by the CDN plugin or the Web SDK.

## Step 8: Clear user

div
div
Client
When the user logs out or the session expires, clear the user so future actions aren’t associated with the previous user. Implement this in your **web application** (e.g., on logout).


```js
const tsClearUserHandler = `
<script>
 async function onUserLogout(event) {
   await window.tsPlatform.drs.clearUser()
 }
 let button = document.getElementById("logout");
 if (button) {
   button.addEventListener('click', onUserLogout);
 }
</script>
`;
```