NestJS CAPTCHA Integration
This recipe shows how to integrate TrustCaptcha into a NestJS application. The frontend setup is the same as for any other Node.js application — this page focuses on the server-side validation.
The setup section gets you to a working integration in three small steps using a controller method directly. Below it, an optional refactor section shows the more reusable NestJS-idiomatic approach (a custom guard wired into the request pipeline).
Preparation
Section titled “Preparation”You should have already completed the following steps before you wire TrustCaptcha into your NestJS application.
Read Get-Started: Get a quick overview of the concepts behind TrustCaptcha and the integration process in get started.
Existing CAPTCHA: If you don’t have a CAPTCHA yet, sign in or create a new user account. Then create a new CAPTCHA.
1. Embed the frontend widget
Section titled “1. Embed the frontend widget”First, add the TrustCaptcha script to your page (see the JavaScript Guide for version pinning and self-hosting options).
Then place the <trustcaptcha-component> element inside your form. The widget appends a hidden tc-verification-token field on submit, which your NestJS controller receives in @Body() like any other form input.
<script type="module" src="https://cdn.trustcomponent.com/trustcaptcha/3.0.x/trustcaptcha.esm.min.js"></script>
<form method="post" action="/contact"> <label>Email</label> <input type="email" name="email" required>
<trustcaptcha-component sitekey="<your_site_key>"></trustcaptcha-component>
<button type="submit">Send</button></form>See the Widget Overview for the full property reference.
2. Install the Node.js SDK
Section titled “2. Install the Node.js SDK”npm i @trustcomponent/trustcaptcha-nodejs@^3.0.03. Validate the token in your controller
Section titled “3. Validate the token in your controller”import { BadRequestException, Body, Controller, Post } from "@nestjs/common";import { TrustCaptcha } from "@trustcomponent/trustcaptcha-nodejs";
class ContactDto { email: string; "tc-verification-token": string;}
@Controller("contact")export class ContactController { @Post() async submit(@Body() body: ContactDto) { // In production, load from env: process.env.TRUSTCAPTCHA_API_KEY const apiKey = "<your_api_key>"; const token = body["tc-verification-token"] ?? "";
try { const result = await TrustCaptcha.getVerificationResult(apiKey, token); if (!result.verificationPassed || result.score > 0.5) { throw new BadRequestException("CAPTCHA verification failed."); } } catch (err) { if (err instanceof BadRequestException) throw err; throw new BadRequestException("CAPTCHA verification failed."); }
// CAPTCHA passed — request data is safe to use. // ... your business logic ...
return { status: "ok" }; }}That’s it — the form is now protected. For real deployments, move the API key out of the source code (see the comment) and consider explicit failover handling — see Failover Behavior for the reasoning and a code template.
Refactor: extract to a guard
Section titled “Refactor: extract to a guard”If you protect more than one endpoint, the most idiomatic NestJS approach is a custom guard. The verification call then runs automatically before any controller method that opts in via @UseGuards(TrustCaptchaGuard).
Configure the API key
Section titled “Configure the API key”Use Nest’s ConfigModule so the API key flows through DI:
npm i @nestjs/configimport { Module } from "@nestjs/common";import { ConfigModule } from "@nestjs/config";import { ContactController } from "./contact/contact.controller";import { TrustCaptchaGuard } from "./common/trust-captcha.guard";
@Module({ imports: [ConfigModule.forRoot({ isGlobal: true })], controllers: [ContactController], providers: [TrustCaptchaGuard],})export class AppModule {}TRUSTCAPTCHA_API_KEY=<your_api_key>Create the guard
Section titled “Create the guard”import { CanActivate, ExecutionContext, Injectable, BadRequestException } from "@nestjs/common";import { ConfigService } from "@nestjs/config";import { TrustCaptcha } from "@trustcomponent/trustcaptcha-nodejs";
@Injectable()export class TrustCaptchaGuard implements CanActivate { private readonly trustCaptcha: TrustCaptcha;
constructor(config: ConfigService) { this.trustCaptcha = new TrustCaptcha({ apiKey: config.getOrThrow<string>("TRUSTCAPTCHA_API_KEY"), }); }
async canActivate(context: ExecutionContext): Promise<boolean> { const req = context.switchToHttp().getRequest(); const token = req.body?.["tc-verification-token"] ?? "";
try { const result = await this.trustCaptcha.getVerificationResult(token); if (!result.verificationPassed || result.score > 0.5) { throw new BadRequestException("CAPTCHA verification failed."); } } catch (err) { if (err instanceof BadRequestException) throw err; throw new BadRequestException("CAPTCHA verification failed."); }
return true; }}Apply the guard to your endpoints
Section titled “Apply the guard to your endpoints”import { UseGuards } from "@nestjs/common";import { TrustCaptchaGuard } from "../common/trust-captcha.guard";
@Controller("contact")export class ContactController { @Post() @UseGuards(TrustCaptchaGuard) async submit(@Body() body: ContactDto) { // CAPTCHA already verified — body is safe to use. return { status: "ok" }; }}A single @UseGuards(TrustCaptchaGuard) decorator now opts any endpoint into CAPTCHA verification. Apply it at the controller level (@UseGuards(...) on the class) to protect every method, or globally (app.useGlobalGuards(...) in main.ts) if every endpoint should require CAPTCHA verification.
Body-parser. Nest enables express.json() and express.urlencoded() by default — req.body is parsed before the guard runs.
ValidationPipe. If you use Nest’s ValidationPipe with class-validator, you can also model the token field on the DTO with a custom decorator. The guard approach above is simpler and works regardless of whether you use ValidationPipe.
Configured SDK options. The guard above creates a single TrustCaptcha instance per guard instance (Nest singletons by default). For configured usage (custom timeouts, proxy, custom API host), pass them in the constructor: new TrustCaptcha({ apiKey, apiHost, proxy, ... }). See the Node.js Guide for the full constructor options.
Next steps
Section titled “Next steps”Once you have wired TrustCaptcha into your NestJS application, you can use TrustCaptcha to its full extent. However, we still recommend the following additional technical and organizational measures:
Security rules: You can find many security settings for your CAPTCHA in the CAPTCHA settings. These include, for example, authorized websites, CAPTCHA bypass for specific IP addresses, bypass keys, IP based blocking, geoblocking, individual difficulty and duration of the CAPTCHA, and much more. Learn more about the security rules.
Privacy & GDPR compliance: Include a passage in your privacy policy that refers to the use of TrustCaptcha. We also recommend that you enter into a data processing agreement with us to stay GDPR-compliant. Learn more about data protection.
Accessibility & UX: Customize TrustCaptcha to your website so that your website is as accessible as possible and offers the best possible user experience. More about accessibility.
Failover behavior: Decide how your backend should behave when our service is temporarily unreachable. This is particularly important for high-availability flows where blocking real users during an outage is worse than letting through a small amount of unverified traffic. Learn more about failover behavior.
Testing: If you use automated testing, make sure that the CAPTCHA does not block it. Learn more about testing.