Configure GCP reCAPTCHA Enterprise Keys

The gcp:recaptcha/enterpriseKey:EnterpriseKey resource, part of the Pulumi GCP provider, defines a reCAPTCHA Enterprise key that validates user interactions across web and mobile platforms. This guide focuses on three capabilities: web integration with score and challenge modes, mobile platform validation for Android and iOS, and WAF integration with Cloud Armor.

reCAPTCHA Enterprise keys belong to a GCP project with the reCAPTCHA Enterprise API enabled. WAF-enabled keys require Cloud Armor configuration. The examples are intentionally small. Combine them with your own domain allowlists, mobile app configurations, and WAF rules.

Create a web key with score-based integration

Most deployments start with a minimal web key that uses score-based integration to assess user interactions invisibly.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.recaptcha.EnterpriseKey("primary", {
    displayName: "display-name-one",
    project: "my-project-name",
    webSettings: {
        integrationType: "SCORE",
        allowAllDomains: true,
    },
    labels: {},
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.recaptcha.EnterpriseKey("primary",
    display_name="display-name-one",
    project="my-project-name",
    web_settings={
        "integration_type": "SCORE",
        "allow_all_domains": True,
    },
    labels={})
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/recaptcha"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := recaptcha.NewEnterpriseKey(ctx, "primary", &recaptcha.EnterpriseKeyArgs{
			DisplayName: pulumi.String("display-name-one"),
			Project:     pulumi.String("my-project-name"),
			WebSettings: &recaptcha.EnterpriseKeyWebSettingsArgs{
				IntegrationType: pulumi.String("SCORE"),
				AllowAllDomains: pulumi.Bool(true),
			},
			Labels: pulumi.StringMap{},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Recaptcha.EnterpriseKey("primary", new()
    {
        DisplayName = "display-name-one",
        Project = "my-project-name",
        WebSettings = new Gcp.Recaptcha.Inputs.EnterpriseKeyWebSettingsArgs
        {
            IntegrationType = "SCORE",
            AllowAllDomains = true,
        },
        Labels = null,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.recaptcha.EnterpriseKey;
import com.pulumi.gcp.recaptcha.EnterpriseKeyArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyWebSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new EnterpriseKey("primary", EnterpriseKeyArgs.builder()
            .displayName("display-name-one")
            .project("my-project-name")
            .webSettings(EnterpriseKeyWebSettingsArgs.builder()
                .integrationType("SCORE")
                .allowAllDomains(true)
                .build())
            .labels(Map.ofEntries(
            ))
            .build());

    }
}
resources:
  primary:
    type: gcp:recaptcha:EnterpriseKey
    properties:
      displayName: display-name-one
      project: my-project-name
      webSettings:
        integrationType: SCORE
        allowAllDomains: true
      labels: {}

The webSettings block configures how the key validates web traffic. Setting integrationType to “SCORE” enables invisible risk scoring without presenting challenges. The allowAllDomains property permits requests from any domain during development; restrict this in production by specifying allowedDomains.

Add visible checkbox challenges for web traffic

Some applications require explicit user interaction through a visible checkbox rather than invisible scoring.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.recaptcha.EnterpriseKey("primary", {
    displayName: "display-name-one",
    project: "my-project-name",
    testingOptions: {
        testingChallenge: "NOCAPTCHA",
        testingScore: 0.5,
    },
    webSettings: {
        integrationType: "CHECKBOX",
        allowAllDomains: true,
        allowedDomains: [],
        challengeSecurityPreference: "USABILITY",
    },
    labels: {
        "label-one": "value-one",
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.recaptcha.EnterpriseKey("primary",
    display_name="display-name-one",
    project="my-project-name",
    testing_options={
        "testing_challenge": "NOCAPTCHA",
        "testing_score": 0.5,
    },
    web_settings={
        "integration_type": "CHECKBOX",
        "allow_all_domains": True,
        "allowed_domains": [],
        "challenge_security_preference": "USABILITY",
    },
    labels={
        "label-one": "value-one",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/recaptcha"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := recaptcha.NewEnterpriseKey(ctx, "primary", &recaptcha.EnterpriseKeyArgs{
			DisplayName: pulumi.String("display-name-one"),
			Project:     pulumi.String("my-project-name"),
			TestingOptions: &recaptcha.EnterpriseKeyTestingOptionsArgs{
				TestingChallenge: pulumi.String("NOCAPTCHA"),
				TestingScore:     pulumi.Float64(0.5),
			},
			WebSettings: &recaptcha.EnterpriseKeyWebSettingsArgs{
				IntegrationType:             pulumi.String("CHECKBOX"),
				AllowAllDomains:             pulumi.Bool(true),
				AllowedDomains:              pulumi.StringArray{},
				ChallengeSecurityPreference: pulumi.String("USABILITY"),
			},
			Labels: pulumi.StringMap{
				"label-one": pulumi.String("value-one"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Recaptcha.EnterpriseKey("primary", new()
    {
        DisplayName = "display-name-one",
        Project = "my-project-name",
        TestingOptions = new Gcp.Recaptcha.Inputs.EnterpriseKeyTestingOptionsArgs
        {
            TestingChallenge = "NOCAPTCHA",
            TestingScore = 0.5,
        },
        WebSettings = new Gcp.Recaptcha.Inputs.EnterpriseKeyWebSettingsArgs
        {
            IntegrationType = "CHECKBOX",
            AllowAllDomains = true,
            AllowedDomains = new() { },
            ChallengeSecurityPreference = "USABILITY",
        },
        Labels = 
        {
            { "label-one", "value-one" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.recaptcha.EnterpriseKey;
import com.pulumi.gcp.recaptcha.EnterpriseKeyArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyTestingOptionsArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyWebSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new EnterpriseKey("primary", EnterpriseKeyArgs.builder()
            .displayName("display-name-one")
            .project("my-project-name")
            .testingOptions(EnterpriseKeyTestingOptionsArgs.builder()
                .testingChallenge("NOCAPTCHA")
                .testingScore(0.5)
                .build())
            .webSettings(EnterpriseKeyWebSettingsArgs.builder()
                .integrationType("CHECKBOX")
                .allowAllDomains(true)
                .allowedDomains()
                .challengeSecurityPreference("USABILITY")
                .build())
            .labels(Map.of("label-one", "value-one"))
            .build());

    }
}
resources:
  primary:
    type: gcp:recaptcha:EnterpriseKey
    properties:
      displayName: display-name-one
      project: my-project-name
      testingOptions:
        testingChallenge: NOCAPTCHA
        testingScore: 0.5
      webSettings:
        integrationType: CHECKBOX
        allowAllDomains: true
        allowedDomains: []
        challengeSecurityPreference: USABILITY
      labels:
        label-one: value-one

Switching integrationType to “CHECKBOX” presents users with a visible challenge. The challengeSecurityPreference property balances security and usability; “USABILITY” prioritizes user experience. The testingOptions block lets you control challenge behavior during development by setting testingChallenge to “NOCAPTCHA” and testingScore to simulate risk levels.

Integrate with Cloud Armor for WAF protection

Applications behind Cloud Armor can present CAPTCHA challenges when suspicious traffic is detected.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.recaptcha.EnterpriseKey("primary", {
    displayName: "display-name-one",
    project: "my-project-name",
    testingOptions: {
        testingChallenge: "NOCAPTCHA",
        testingScore: 0.5,
    },
    wafSettings: {
        wafFeature: "CHALLENGE_PAGE",
        wafService: "CA",
    },
    webSettings: {
        integrationType: "INVISIBLE",
        allowAllDomains: true,
        allowedDomains: [],
        challengeSecurityPreference: "USABILITY",
    },
    labels: {
        "label-one": "value-one",
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.recaptcha.EnterpriseKey("primary",
    display_name="display-name-one",
    project="my-project-name",
    testing_options={
        "testing_challenge": "NOCAPTCHA",
        "testing_score": 0.5,
    },
    waf_settings={
        "waf_feature": "CHALLENGE_PAGE",
        "waf_service": "CA",
    },
    web_settings={
        "integration_type": "INVISIBLE",
        "allow_all_domains": True,
        "allowed_domains": [],
        "challenge_security_preference": "USABILITY",
    },
    labels={
        "label-one": "value-one",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/recaptcha"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := recaptcha.NewEnterpriseKey(ctx, "primary", &recaptcha.EnterpriseKeyArgs{
			DisplayName: pulumi.String("display-name-one"),
			Project:     pulumi.String("my-project-name"),
			TestingOptions: &recaptcha.EnterpriseKeyTestingOptionsArgs{
				TestingChallenge: pulumi.String("NOCAPTCHA"),
				TestingScore:     pulumi.Float64(0.5),
			},
			WafSettings: &recaptcha.EnterpriseKeyWafSettingsArgs{
				WafFeature: pulumi.String("CHALLENGE_PAGE"),
				WafService: pulumi.String("CA"),
			},
			WebSettings: &recaptcha.EnterpriseKeyWebSettingsArgs{
				IntegrationType:             pulumi.String("INVISIBLE"),
				AllowAllDomains:             pulumi.Bool(true),
				AllowedDomains:              pulumi.StringArray{},
				ChallengeSecurityPreference: pulumi.String("USABILITY"),
			},
			Labels: pulumi.StringMap{
				"label-one": pulumi.String("value-one"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Recaptcha.EnterpriseKey("primary", new()
    {
        DisplayName = "display-name-one",
        Project = "my-project-name",
        TestingOptions = new Gcp.Recaptcha.Inputs.EnterpriseKeyTestingOptionsArgs
        {
            TestingChallenge = "NOCAPTCHA",
            TestingScore = 0.5,
        },
        WafSettings = new Gcp.Recaptcha.Inputs.EnterpriseKeyWafSettingsArgs
        {
            WafFeature = "CHALLENGE_PAGE",
            WafService = "CA",
        },
        WebSettings = new Gcp.Recaptcha.Inputs.EnterpriseKeyWebSettingsArgs
        {
            IntegrationType = "INVISIBLE",
            AllowAllDomains = true,
            AllowedDomains = new() { },
            ChallengeSecurityPreference = "USABILITY",
        },
        Labels = 
        {
            { "label-one", "value-one" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.recaptcha.EnterpriseKey;
import com.pulumi.gcp.recaptcha.EnterpriseKeyArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyTestingOptionsArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyWafSettingsArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyWebSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new EnterpriseKey("primary", EnterpriseKeyArgs.builder()
            .displayName("display-name-one")
            .project("my-project-name")
            .testingOptions(EnterpriseKeyTestingOptionsArgs.builder()
                .testingChallenge("NOCAPTCHA")
                .testingScore(0.5)
                .build())
            .wafSettings(EnterpriseKeyWafSettingsArgs.builder()
                .wafFeature("CHALLENGE_PAGE")
                .wafService("CA")
                .build())
            .webSettings(EnterpriseKeyWebSettingsArgs.builder()
                .integrationType("INVISIBLE")
                .allowAllDomains(true)
                .allowedDomains()
                .challengeSecurityPreference("USABILITY")
                .build())
            .labels(Map.of("label-one", "value-one"))
            .build());

    }
}
resources:
  primary:
    type: gcp:recaptcha:EnterpriseKey
    properties:
      displayName: display-name-one
      project: my-project-name
      testingOptions:
        testingChallenge: NOCAPTCHA
        testingScore: 0.5
      wafSettings:
        wafFeature: CHALLENGE_PAGE
        wafService: CA
      webSettings:
        integrationType: INVISIBLE
        allowAllDomains: true
        allowedDomains: []
        challengeSecurityPreference: USABILITY
      labels:
        label-one: value-one

The wafSettings block connects the key to Cloud Armor. Setting wafFeature to “CHALLENGE_PAGE” tells Cloud Armor to present a CAPTCHA when WAF rules trigger. The wafService property specifies “CA” for Cloud Armor. This configuration requires integrationType “INVISIBLE” in webSettings to work with WAF challenge pages.

Protect Android apps with package validation

Mobile applications need platform-specific keys that validate requests come from authorized app packages.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.recaptcha.EnterpriseKey("primary", {
    displayName: "display-name-one",
    androidSettings: {
        allowAllPackageNames: true,
        allowedPackageNames: [],
    },
    project: "my-project-name",
    testingOptions: {
        testingScore: 0.8,
    },
    labels: {
        "label-one": "value-one",
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.recaptcha.EnterpriseKey("primary",
    display_name="display-name-one",
    android_settings={
        "allow_all_package_names": True,
        "allowed_package_names": [],
    },
    project="my-project-name",
    testing_options={
        "testing_score": 0.8,
    },
    labels={
        "label-one": "value-one",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/recaptcha"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := recaptcha.NewEnterpriseKey(ctx, "primary", &recaptcha.EnterpriseKeyArgs{
			DisplayName: pulumi.String("display-name-one"),
			AndroidSettings: &recaptcha.EnterpriseKeyAndroidSettingsArgs{
				AllowAllPackageNames: pulumi.Bool(true),
				AllowedPackageNames:  pulumi.StringArray{},
			},
			Project: pulumi.String("my-project-name"),
			TestingOptions: &recaptcha.EnterpriseKeyTestingOptionsArgs{
				TestingScore: pulumi.Float64(0.8),
			},
			Labels: pulumi.StringMap{
				"label-one": pulumi.String("value-one"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Recaptcha.EnterpriseKey("primary", new()
    {
        DisplayName = "display-name-one",
        AndroidSettings = new Gcp.Recaptcha.Inputs.EnterpriseKeyAndroidSettingsArgs
        {
            AllowAllPackageNames = true,
            AllowedPackageNames = new() { },
        },
        Project = "my-project-name",
        TestingOptions = new Gcp.Recaptcha.Inputs.EnterpriseKeyTestingOptionsArgs
        {
            TestingScore = 0.8,
        },
        Labels = 
        {
            { "label-one", "value-one" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.recaptcha.EnterpriseKey;
import com.pulumi.gcp.recaptcha.EnterpriseKeyArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyAndroidSettingsArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyTestingOptionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new EnterpriseKey("primary", EnterpriseKeyArgs.builder()
            .displayName("display-name-one")
            .androidSettings(EnterpriseKeyAndroidSettingsArgs.builder()
                .allowAllPackageNames(true)
                .allowedPackageNames()
                .build())
            .project("my-project-name")
            .testingOptions(EnterpriseKeyTestingOptionsArgs.builder()
                .testingScore(0.8)
                .build())
            .labels(Map.of("label-one", "value-one"))
            .build());

    }
}
resources:
  primary:
    type: gcp:recaptcha:EnterpriseKey
    properties:
      displayName: display-name-one
      androidSettings:
        allowAllPackageNames: true
        allowedPackageNames: []
      project: my-project-name
      testingOptions:
        testingScore: 0.8
      labels:
        label-one: value-one

The androidSettings block replaces webSettings for mobile apps. Setting allowAllPackageNames to true permits any package during development; restrict this by listing specific package names in allowedPackageNames. The testingScore property simulates risk scores during development without requiring real user interactions.

Protect iOS apps with bundle ID validation

iOS applications require keys that validate bundle IDs to ensure requests originate from legitimate installations.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.recaptcha.EnterpriseKey("primary", {
    displayName: "display-name-one",
    iosSettings: {
        allowAllBundleIds: true,
        allowedBundleIds: [],
    },
    project: "my-project-name",
    testingOptions: {
        testingScore: 1,
    },
    labels: {
        "label-one": "value-one",
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.recaptcha.EnterpriseKey("primary",
    display_name="display-name-one",
    ios_settings={
        "allow_all_bundle_ids": True,
        "allowed_bundle_ids": [],
    },
    project="my-project-name",
    testing_options={
        "testing_score": 1,
    },
    labels={
        "label-one": "value-one",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/recaptcha"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := recaptcha.NewEnterpriseKey(ctx, "primary", &recaptcha.EnterpriseKeyArgs{
			DisplayName: pulumi.String("display-name-one"),
			IosSettings: &recaptcha.EnterpriseKeyIosSettingsArgs{
				AllowAllBundleIds: pulumi.Bool(true),
				AllowedBundleIds:  pulumi.StringArray{},
			},
			Project: pulumi.String("my-project-name"),
			TestingOptions: &recaptcha.EnterpriseKeyTestingOptionsArgs{
				TestingScore: pulumi.Float64(1),
			},
			Labels: pulumi.StringMap{
				"label-one": pulumi.String("value-one"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.Recaptcha.EnterpriseKey("primary", new()
    {
        DisplayName = "display-name-one",
        IosSettings = new Gcp.Recaptcha.Inputs.EnterpriseKeyIosSettingsArgs
        {
            AllowAllBundleIds = true,
            AllowedBundleIds = new() { },
        },
        Project = "my-project-name",
        TestingOptions = new Gcp.Recaptcha.Inputs.EnterpriseKeyTestingOptionsArgs
        {
            TestingScore = 1,
        },
        Labels = 
        {
            { "label-one", "value-one" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.recaptcha.EnterpriseKey;
import com.pulumi.gcp.recaptcha.EnterpriseKeyArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyIosSettingsArgs;
import com.pulumi.gcp.recaptcha.inputs.EnterpriseKeyTestingOptionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new EnterpriseKey("primary", EnterpriseKeyArgs.builder()
            .displayName("display-name-one")
            .iosSettings(EnterpriseKeyIosSettingsArgs.builder()
                .allowAllBundleIds(true)
                .allowedBundleIds()
                .build())
            .project("my-project-name")
            .testingOptions(EnterpriseKeyTestingOptionsArgs.builder()
                .testingScore(1.0)
                .build())
            .labels(Map.of("label-one", "value-one"))
            .build());

    }
}
resources:
  primary:
    type: gcp:recaptcha:EnterpriseKey
    properties:
      displayName: display-name-one
      iosSettings:
        allowAllBundleIds: true
        allowedBundleIds: []
      project: my-project-name
      testingOptions:
        testingScore: 1
      labels:
        label-one: value-one

The iosSettings block configures iOS-specific validation. Setting allowAllBundleIds to true permits any bundle ID during development; restrict this by listing specific bundle IDs in allowedBundleIds. Like Android keys, testingScore simulates risk assessment during development.

Beyond these examples

These snippets focus on specific key-level features: web integration (score-based and challenge-based), mobile platform validation (Android and iOS), and WAF integration with Cloud Armor. They’re intentionally minimal rather than full bot protection systems.

The examples may reference pre-existing infrastructure such as a GCP project with reCAPTCHA Enterprise API enabled, and Cloud Armor WAF configuration for WAF examples. They focus on configuring the key rather than provisioning the surrounding infrastructure.

To keep things focused, common key patterns are omitted, including:

  • Domain allowlists (allowedDomains for restricted access)
  • AMP traffic handling (allowAmpTraffic)
  • Package/bundle ID restrictions (when not using allowAll)
  • Custom testing challenges and scores

These omissions are intentional: the goal is to illustrate how each key feature is wired, not provide drop-in bot protection modules. See the reCAPTCHA Enterprise Key resource reference for all available configuration options.

Let's configure GCP reCAPTCHA Enterprise Keys

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Platform & Configuration
How do I choose between Android, iOS, and web settings?
Choose one platform setting based on where your key will be used: androidSettings for Android apps, iosSettings for iOS apps, or webSettings for websites. You cannot configure multiple platform settings on the same key.
What are the web integration types and when should I use each?
SCORE provides invisible risk analysis without user interaction, CHECKBOX displays the traditional “I’m not a robot” checkbox, and INVISIBLE only challenges users when suspicious activity is detected. Choose based on your user experience requirements.
Should I use allowAllDomains or specify allowed domains?
Set allowAllDomains to true for development or if your key needs to work across many domains. For production, specify allowedDomains explicitly for better security. The same pattern applies to allowAllPackageNames (Android) and allowAllBundleIds (iOS).
Testing & Development
What are testing options used for?
Testing options let you control reCAPTCHA behavior during user acceptance testing without affecting production traffic. Set testingScore (0.0 to 1.0) to return a specific score, or use testingChallenge to control challenge behavior.
What testing score should I use during development?
Use testingScore values between 0.5 and 1.0 for testing. Examples show 0.5 for typical testing, 0.8 for stricter validation, and 1.0 for always-passing tests.
Immutability & Updates
What properties can't be changed after the key is created?
The project, testingOptions, and wafSettings properties are immutable. Changing any of these requires replacing the entire key resource.
Can I update the display name or labels after creation?
Yes, displayName is modifiable by users, and labels can be updated. However, labels is non-authoritative, so use effectiveLabels to see all labels present on the resource.
Labels & Metadata
Why don't my labels match what I configured?
The labels field is non-authoritative and only manages labels in your configuration. Other clients and services may add additional labels. Use the effectiveLabels output property to see all labels present on the resource in GCP.
WAF Integration
How do I configure reCAPTCHA for WAF (Web Application Firewall)?
Set wafSettings with wafFeature (like CHALLENGE_PAGE) and wafService (like CA for Cloud Armor). Note that wafSettings is immutable after creation.

Using a different cloud?

Explore security guides for other cloud providers: