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: score-based and challenge-based verification modes, platform-specific keys for Android, iOS, and web, and WAF integration for edge-layer protection.

reCAPTCHA keys belong to a GCP project with the reCAPTCHA Enterprise API enabled. Each key is configured for a specific platform (web, Android, or iOS) and integration type. The examples are intentionally small. Combine them with your own domain restrictions and production security settings.

Create a score-based key for web applications

Most deployments start with score-based verification that evaluates user interactions without showing challenges, providing baseline bot detection.

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 the key for websites. Setting integrationType to “SCORE” enables risk scoring without user-facing challenges. The allowAllDomains property permits testing from any domain; in production, replace this with allowedDomains to restrict usage to your domains.

Show checkbox challenges to verify users

Applications that need explicit verification can display checkbox challenges, requiring users to click “I’m not a robot.”

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

Setting integrationType to “CHECKBOX” displays the familiar checkbox challenge. The testingOptions block configures behavior during development: testingChallenge determines which challenge type appears, and testingScore sets the risk score returned for test traffic. The challengeSecurityPreference balances security strictness against user experience.

Protect Android apps with package name 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 Android apps. Setting allowAllPackageNames to true permits any package during development; for production, set it to false and list authorized packages in allowedPackageNames. The testingScore property controls risk scores returned during testing.

Protect iOS apps with bundle ID validation

iOS applications require keys that validate bundle IDs to ensure requests come from authorized apps.

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. Like Android keys, allowAllBundleIds permits any bundle during development. For production, restrict access by setting it to false and listing authorized bundle IDs in allowedBundleIds.

Integrate with WAF for challenge page delivery

Web Application Firewalls can serve reCAPTCHA challenge pages directly, blocking suspicious traffic before it reaches your application.

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 enables WAF integration. Setting wafFeature to “CHALLENGE_PAGE” tells the WAF to serve challenge pages for suspicious requests. The wafService property specifies which WAF provider you’re using (CA for Cloud Armor). This configuration works with INVISIBLE integration type, which triggers challenges only when needed.

Beyond these examples

These snippets focus on specific key-level features: score-based and challenge-based verification, platform-specific validation for Android, iOS, and web, and WAF integration. They’re intentionally minimal rather than full bot protection implementations.

The examples assume pre-existing infrastructure such as a GCP project with the reCAPTCHA Enterprise API enabled. They focus on configuring the key rather than provisioning the surrounding project infrastructure.

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

  • Domain restrictions (allowedDomains for production)
  • AMP traffic handling (allowAmpTraffic)
  • Package/bundle name restrictions (for production mobile apps)
  • Testing challenge types beyond NOCAPTCHA

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 & Integration Types
Can I use one reCAPTCHA Enterprise key for multiple platforms?
No, each key is platform-specific. Configure androidSettings for Android apps, iosSettings for iOS apps, or webSettings for websites.
What integration types are available for web keys?

Web keys support three integration types in webSettings:

  1. SCORE - Risk score without user interaction
  2. CHECKBOX - Traditional reCAPTCHA challenge
  3. INVISIBLE - Invisible challenge that triggers when needed
Testing & Development
How do I test my reCAPTCHA key during development?
Configure testingOptions with testingScore (0.0 to 1.0) to control the score returned during testing. You can also set testingChallenge to NOCAPTCHA to skip the challenge.
Configuration & Restrictions
Should I allow all domains or restrict to specific domains?

You have two options:

  • Permissive: Set allowAllDomains: true (or allowAllPackageNames/allowAllBundleIds for mobile)
  • Restricted: Set allowAllDomains: false and specify allowedDomains array

The same pattern applies to Android package names and iOS bundle IDs.

How do I integrate reCAPTCHA with Web Application Firewall?
Configure wafSettings with wafFeature (e.g., CHALLENGE_PAGE) and wafService (e.g., CA for Cloud Armor). WAF keys also require webSettings configuration.
Can I use reCAPTCHA with AMP pages?
Yes, set allowAmpTraffic: true in webSettings when using SCORE integration type.
Why don't I see all labels in my configuration?
The labels field is non-authoritative and only manages labels present in your configuration. Use effectiveLabels to see all labels present on the resource in GCP, including those set by other clients and services.
Immutability & Updates
What properties can't I change after creating a key?

Three properties are immutable after creation:

  • project - The GCP project
  • testingOptions - Testing configuration
  • wafSettings - WAF integration settings

Using a different cloud?

Explore security guides for other cloud providers: