How I Built an AI Tattoo Generator with Next.js, Cloudflare, Google OAuth, and PayPal
I recently shipped BodyInk.art, an AI tattoo generator that helps users explore tattoo concepts before going to a studio.
In this post, I want to share the engineering side: what worked, what broke in production, and what I changed to make the app stable.
The Product Goal
Tattoo ideation is often slow:
- users collect references from many places
- style direction is unclear early on
- multiple revision rounds happen before a final direction
I wanted a workflow where users can type an idea, generate concepts quickly, and download results for discussion with tattoo artists.
Stack Choice
I used:
- Next.js App Router for pages and API routes
- Cloudflare Pages for deployment
- Google OAuth (NextAuth) for sign-in
- PayPal for pay-per-generation
- an AI image backend for tattoo image generation
This stack gave me fast iteration and global delivery, but it also exposed some runtime differences I had to handle.
The First Real Production Bug
After deployment, image generation failed with:
Cannot read properties of null (reading 'has')
At first it looked like a random null bug, but the root cause was runtime incompatibility. A dependency path assumed Node-like behavior, while the deployed environment executed in an Edge-like context.
What fixed it
I replaced the problematic SDK-dependent path with a simpler fetch-based implementation and removed Node-only assumptions from the generation flow.
Result:
- no more random null access in the hot path
- easier debugging because request/response behavior became explicit
Base64 and Edge Runtime Gotchas
Another source of 500 errors was image encoding. The naive conversion strategy caused performance and reliability issues under constrained runtime conditions.
I switched to chunked Uint8Array processing instead of relying on heavier Node-oriented patterns. This reduced pressure on runtime limits and made generation responses stable.
If you process image buffers on serverless/edge platforms, don’t assume desktop Node behavior will hold.
Adding Google OAuth with NextAuth
I integrated Google sign-in using NextAuth with callback route:
/api/auth/callback/google
Implementation notes:
- keep OAuth credentials in environment variables
- define the correct
NEXTAUTH_URLper environment - verify provider callback settings match your production domain exactly
The biggest practical issue is usually config mismatch, not code.
Adding PayPal: Sandbox First, Then Live
The business rule is simple: $1 per generation.
I implemented two endpoints:
- create order
- capture payment
And I kept env-driven mode switching so I could test safely in Sandbox and then move to Live.
Important details:
- lock amount/currency on the server side
- never trust client-only payment state
- return clear failure messages to avoid silent checkout errors
SEO and Analytics
After core flows worked, I optimized discoverability:
- improved page-level metadata
- added sitemap and robots
- integrated Google Analytics globally
For analytics in Next.js App Router, a framework-aligned integration keeps scripts cleaner and avoids layout-level duplication.
Lessons Learned
- Runtime differences matter more than local success.
- Keep payment logic server-authoritative.
- Integrations fail more from misconfiguration than code defects.
- Production debugging gets easier when dependencies are minimal in critical paths.
What I’d Improve Next
- better prompt guidance for first-time users
- stronger style consistency controls
- smarter retry/fallback strategy for generation failures
- clearer pricing and credit UX
Final Thoughts
Shipping AI features is not just model quality. It is mostly engineering reliability:
- predictable runtime behavior
- robust payment flow
- traceable errors
- fast iteration loop
If you’re building a similar AI product on Next.js + Cloudflare, I hope this saves you a few painful nights.
If you want, I can share a follow-up post with concrete route structure, env templates, and a deployment checklist.
Top comments (0)