Building a Next.js NSFW Text-to-Image AI Generator with React and Sentry

Building a Next.js NSFW Text-to-Image AI Generator with React and Sentry In the ever-evolving world of AI and web development, creating applications that can generate images from text prompts is a fascinating challenge. In this article, we’ll explore how to build a text-to-image AI NSFW generator using Next.js, React, TypeScript, Tailwind CSS, and Sentry, with tracking via Facebook Pixel. We’ll cover project setup, Tailwind configuration, Sentry initialization, the core text-to-image API integration, NSFW moderation, frontend UI, error handling, performance monitoring, and deployment. Code snippets are provided throughout so you can follow along hands-on. Introduction Text-to-image generation has seen rapid progress thanks to powerful models such as OpenAI’s DALL·E series or Stability AI’s Stable Diffusion. By integrating these APIs into a modern web stack, you can give users the creative freedom to describe scenes, characters, or abstract concepts—and see them visualized. At the same time, responsible handling of potentially NSFW content is crucial. In this guide, we’ll show you how to: Spin up a Next.js + TypeScript starter Style with Tailwind CSS Initialize Sentry for error and performance tracking Call a text-to-image AI API Run moderation on NSFW prompts and outputs Add Facebook Pixel for analytics Build a responsive React UI Deploy the finished app to Vercel Let’s get started! Technologies Used Next.js – Server-side rendering, API routes, and static exports. React – Component-driven UI. TypeScript – Strong typing for reliability. Tailwind CSS – Utility-first styling for rapid layout. Sentry – Error tracking & performance monitoring. Facebook Pixel – User interaction and conversion analytics. OpenAI / Stability AI API – Backend text-to-image endpoint. NSFW Moderation API – Built-in or third-party endpoint to filter content. Setting Up the Next.js Project Open your terminal and run: npx create-next-app@latest --ts nsfw-text-to-image-generator cd nsfw-text-to-image-generator Install core dependencies: npm install react react-dom next @sentry/nextjs tailwindcss postcss autoprefixer Initialize Tailwind CSS: npx tailwindcss init -p Configuring Tailwind CSS Edit tailwind.config.js to include your Next.js pages and components: module.exports = { content: [ "./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [], } Add the Tailwind directives to styles/globals.css: @tailwind base; @tailwind components; @tailwind utilities; Initializing Sentry Sentry helps capture exceptions and performance metrics across both server and client. Run the Sentry init: npx @sentry/wizard -i nextjs This will install @sentry/nextjs and generate sentry.server.config.js and sentry.client.config.js. Configure your DSN in .env.local: NEXT_PUBLIC_SENTRY_DSN=https://yourPublicDsn@sentry.io/1234567 SENTRY_ORG=your-org SENTRY_PROJECT=your-project Wrap your application in Sentry’s error boundary. In pages/_app.tsx: import { AppProps } from 'next/app'; import { ErrorBoundary } from '@sentry/react'; import '@/styles/globals.css'; function MyApp({ Component, pageProps }: AppProps) { return ( ); } export default MyApp; Environment Variables Create .env.local at the project root: NEXT_PUBLIC_OPENAI_API_KEY=sk-xxx… NEXT_PUBLIC_SENTRY_DSN=https://… NEXT_PUBLIC_FACEBOOK_PIXEL_ID=1234567890 MODERATION_API_KEY=mod-yyy… Restart your dev server after changing env vars. Building the Text-to-Image API Route In pages/api/generate.ts, we’ll call the AI image API and run content moderation: import type { NextApiRequest, NextApiResponse } from 'next'; import Sentry from '@sentry/nextjs'; const OPENAI_API_KEY = process.env.NEXT_PUBLIC_OPENAI_API_KEY!; const MOD_API_KEY = process.env.MODERATION_API_KEY!; type Data = { imageUrl?: string; error?: string }; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { Sentry.captureMessage('API route invoked', 'info'); if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); } const { prompt } = req.body; if (!prompt) { return res.status(400).json({ error: 'Prompt is required' }); } // 1. Moderate the prompt const modResponse = await fetch('https://api.moderation.example/v1/check', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${MOD_API_KEY}`, }, body: JSON.stringify({ text: prompt }), }); const modResult = await modResponse.json(); if (modResult.flagged) { return res.status(403).json({ error: 'Prompt flagged as NSFW' }); } try { // 2. Generate the image const aiRes = await fetch('https://api.o

May 1, 2025 - 04:46
 0
Building a Next.js NSFW Text-to-Image AI Generator with React and Sentry

Building a Next.js NSFW Text-to-Image AI Generator with React and Sentry

In the ever-evolving world of AI and web development, creating applications that can generate images from text prompts is a fascinating challenge. In this article, we’ll explore how to build a text-to-image AI NSFW generator using Next.js, React, TypeScript, Tailwind CSS, and Sentry, with tracking via Facebook Pixel. We’ll cover project setup, Tailwind configuration, Sentry initialization, the core text-to-image API integration, NSFW moderation, frontend UI, error handling, performance monitoring, and deployment. Code snippets are provided throughout so you can follow along hands-on.

Introduction

Text-to-image generation has seen rapid progress thanks to powerful models such as OpenAI’s DALL·E series or Stability AI’s Stable Diffusion. By integrating these APIs into a modern web stack, you can give users the creative freedom to describe scenes, characters, or abstract concepts—and see them visualized. At the same time, responsible handling of potentially NSFW content is crucial. In this guide, we’ll show you how to:

  1. Spin up a Next.js + TypeScript starter
  2. Style with Tailwind CSS
  3. Initialize Sentry for error and performance tracking
  4. Call a text-to-image AI API
  5. Run moderation on NSFW prompts and outputs
  6. Add Facebook Pixel for analytics
  7. Build a responsive React UI
  8. Deploy the finished app to Vercel

Let’s get started!

Technologies Used

  • Next.js – Server-side rendering, API routes, and static exports.
  • React – Component-driven UI.
  • TypeScript – Strong typing for reliability.
  • Tailwind CSS – Utility-first styling for rapid layout.
  • Sentry – Error tracking & performance monitoring.
  • Facebook Pixel – User interaction and conversion analytics.
  • OpenAI / Stability AI API – Backend text-to-image endpoint.
  • NSFW Moderation API – Built-in or third-party endpoint to filter content.

Setting Up the Next.js Project

Open your terminal and run:

npx create-next-app@latest --ts nsfw-text-to-image-generator
cd nsfw-text-to-image-generator

Install core dependencies:

npm install react react-dom next @sentry/nextjs tailwindcss postcss autoprefixer

Initialize Tailwind CSS:

npx tailwindcss init -p

Configuring Tailwind CSS

Edit tailwind.config.js to include your Next.js pages and components:

module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Add the Tailwind directives to styles/globals.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Initializing Sentry

Sentry helps capture exceptions and performance metrics across both server and client.

  1. Run the Sentry init:
   npx @sentry/wizard -i nextjs

This will install @sentry/nextjs and generate sentry.server.config.js and sentry.client.config.js.

  1. Configure your DSN in .env.local:
   NEXT_PUBLIC_SENTRY_DSN=https://yourPublicDsn@sentry.io/1234567
   SENTRY_ORG=your-org
   SENTRY_PROJECT=your-project
  1. Wrap your application in Sentry’s error boundary. In pages/_app.tsx:
   import { AppProps } from 'next/app';
   import { ErrorBoundary } from '@sentry/react';
   import '@/styles/globals.css';

   function MyApp({ Component, pageProps }: AppProps) {
     return (
       <ErrorBoundary fallback={<p>Something went wrong.p>}>
         <Component {...pageProps} />
       ErrorBoundary>
     );
   }

   export default MyApp;

Environment Variables

Create .env.local at the project root:

NEXT_PUBLIC_OPENAI_API_KEY=sk-xxx…
NEXT_PUBLIC_SENTRY_DSN=https://…
NEXT_PUBLIC_FACEBOOK_PIXEL_ID=1234567890
MODERATION_API_KEY=mod-yyy…

Restart your dev server after changing env vars.

Building the Text-to-Image API Route

In pages/api/generate.ts, we’ll call the AI image API and run content moderation:

import type { NextApiRequest, NextApiResponse } from 'next';
import Sentry from '@sentry/nextjs';

const OPENAI_API_KEY = process.env.NEXT_PUBLIC_OPENAI_API_KEY!;
const MOD_API_KEY = process.env.MODERATION_API_KEY!;

type Data = { imageUrl?: string; error?: string };

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  Sentry.captureMessage('API route invoked', 'info');
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { prompt } = req.body;
  if (!prompt) {
    return res.status(400).json({ error: 'Prompt is required' });
  }

  // 1. Moderate the prompt
  const modResponse = await fetch('https://api.moderation.example/v1/check', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${MOD_API_KEY}`,
    },
    body: JSON.stringify({ text: prompt }),
  });
  const modResult = await modResponse.json();
  if (modResult.flagged) {
    return res.status(403).json({ error: 'Prompt flagged as NSFW' });
  }

  try {
    // 2. Generate the image
    const aiRes = await fetch('https://api.openai.com/v1/images/generations', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${OPENAI_API_KEY}`,
      },
      body: JSON.stringify({
        prompt,
        n: 1,
        size: '512x512',
      }),
    });
    const aiData = await aiRes.json();
    const imageUrl = aiData.data[0].url;

    // 3. Optionally moderate the resulting image URL
    // ... (similar to above, using an image moderation endpoint)

    res.status(200).json({ imageUrl });
  } catch (err) {
    Sentry.captureException(err);
    res.status(500).json({ error: 'Failed to generate image' });
  }
}

Handling NSFW Content

  • Prompt Moderation: Check the user’s text before sending it to the AI.
  • Image Moderation: After generation, you can run another check on the image (e.g., via a pixel-based NSFW detection API).
  • User Feedback: If flagged, return a friendly error like “Your prompt contained disallowed content.”

Integrating Facebook Pixel

In pages/_document.tsx, insert the Pixel snippet in the :

import Document, { Html, Head, Main, NextScript } from 'next/document';

class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head>
          {/* Facebook Pixel */}
          <script
            dangerouslySetInnerHTML={{
              __html: `
              !function(f,b,e,v,n,t,s)
              {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
              n.callMethod.apply(n,arguments):n.queue.push(arguments)};
              if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
              n.queue=[];t=b.createElement(e);t.async=!0;
              t.src=v;s=b.getElementsByTagName(e)[0];
              s.parentNode.insertBefore(t,s)}(window, document,'script',
              'https://connect.facebook.net/en_US/fbevents.js');
              fbq('init', '${process.env.NEXT_PUBLIC_FACEBOOK_PIXEL_ID}');
              fbq('track', 'PageView');
            `,
            }}
          />
        Head>
        <body>
          <Main />
          <NextScript />
        body>
      Html>
    );
  }
}

export default MyDocument;

Track custom events when the user generates or downloads an image:

import Router from 'next/router';

export function trackImageGenerated() {
  if (typeof window !== 'undefined' && window.fbq) {
    window.fbq('track', 'GenerateImagе');
  }
}

Router.events.on('routeChangeComplete', () => {
  if (Router.pathname === '/result') {
    trackImageGenerated();
  }
});

Building the Frontend UI

Create a simple form component in components/PromptForm.tsx:

import { useState } from 'react';
import { trackImageGenerated } from '@/lib/facebook';

export default function PromptForm() {
  const [prompt, setPrompt] = useState('');
  const [imageUrl, setImageUrl] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError(null);
    setImageUrl(null);

    const res = await fetch('/api/generate', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ prompt }),
    });
    const data = await res.json();
    setLoading(false);

    if (data.error) {
      setError(data.error);
    } else if (data.imageUrl) {
      setImageUrl(data.imageUrl);
      trackImageGenerated();
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <textarea
        value={prompt}
        onChange={(e) => setPrompt(e.target.value)}
        placeholder="Describe your image..."
        className="w-full p-3 border rounded"
        rows={4}
      />
      <button
        type="submit"
        disabled={loading}
        className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
      >
        {loading ? 'Generating…' : 'Generate Image'}
      button>
      {error && <p className="text-red-500">{error}p>}
      {imageUrl && (
        <div className="mt-4">
          <img src={imageUrl} alt="Generated" className="rounded shadow" />
        div>
      )}
    form>
  );
}

Include this in pages/index.tsx:

import PromptForm from '@/components/PromptForm';

export default function Home() {
  return (
    <main className="min-h-screen flex items-center justify-center p-6">
      <div className="max-w-lg w-full">
        <h1 className="text-3xl font-bold mb-6">
          NSFW Text-to-Image Generator
        h1>
        <PromptForm />
      div>
    main>
  );
}

Error Handling & Performance Monitoring

  • All unhandled exceptions in API routes and React components are captured by Sentry.
  • Use Sentry’s Performance tab to inspect slow API calls or React render bottlenecks.
  • In development, set SENTRY_DEBUG=true to see verbose logs.

Deployment to Vercel

  1. Push your code to GitHub.
  2. Import the repo in Vercel and set your environment variables in the Vercel dashboard.
  3. Choose “Next.js” as the framework and click “Deploy.”

Vercel will handle SSR, API routes, and static assets out of the box.

Conclusion

You’ve now built a full-fledged NSFW-aware text-to-image AI generator with Next.js, React, TypeScript, Tailwind CSS, Sentry, and Facebook Pixel tracking. From secure prompt moderation and AI integration to error monitoring and analytics, this architecture provides a solid foundation for any AI-driven creative app. Feel free to extend it—for example, by adding user authentication, credit-based usage, or a gallery of saved images. Happy coding!