Making AI dating photos that don't look AI-generated (the negative prompt matters more than the model) A developer building an AI dating photo tool found that negative prompts targeting skin texture are more critical than the model choice for avoiding the telltale AI-generated look. The tool uses two fal.ai calls per image—flux-pulid for identity preservation and a clarity upscaler for skin texture—with a negative prompt including 'waxy skin' and 'plastic skin' to combat photorealism failures. Cloudflare Pages Functions generate one style per request to avoid timeouts, and an HMAC-signed grant system prevents unauthorized API calls. I already wrote about https://dev.to/kunstudio/i-built-an-ai-headshot-tool-that-keeps-the-actual-face-flux-pulid-instead-of-pure-diffusion-3m46 why identity-preservation models like fal.ai's flux-pulid beat LoRA fine-tuning for keeping a face recognizable. Building AI Dating Photos on the same model surfaced a different, harder problem: keeping the skin recognizable. Identity-preserving generation solves "does this still look like the same person." It does nothing for "does this look like a real photograph," and for a dating profile picture, the second failure mode is the one that gets someone unmatched — that telltale waxy, over-smoothed, poreless AI skin is instantly recognizable to anyone who's swiped past a few AI-generated profiles already. Every generation is two fal.ai calls, not one: fal-ai/flux-pulid — generates the styled photo from the reference selfie, tuned with num inference steps: 26 above the model's 20-step default and id weight: 1.0 for a hard face lock. fal-ai/clarity-upscaler — a finishing pass with creativity: 0.3 , resemblance: 1.5 , run purely to reintroduce real skin texture and kill plastic/CGI artifacts, not to increase resolution as a goal in itself.The negative prompt carried through both stages is doing most of the actual work against the "looks AI" problem: waxy skin, plastic skin, airbrushed, over-smooth skin, poreless skin, beauty filter, oversaturated sit right alongside the more expected deformed, extra fingers, blurry . Most negative-prompt lists you'll find in tutorials stop at the structural failure modes extra limbs, wrong eye count because those are the obviously broken outputs. The skin-texture terms exist because a structurally correct face with plastic skin is arguably the more common failure mode for a photoreal use case, and it's the one that actually kills conversion on a dating-photo product specifically. The Cloudflare Pages Function behind this doesn't generate a full batch of every style in one request — it generates one style per call, and the browser loops through styles client-side. That's not an accident of the code, it's a direct consequence of Cloudflare Functions' CPU/wall-time limits: flux-pulid generation plus an upscale pass, polled at 1.5s intervals with up to 60 polls, can run long enough that bundling four styles into one request risks the whole batch timing out and the user getting nothing. Splitting by style means a slow style can fail or time out without taking the other three down with it. There's no order table anywhere in this flow. Checkout produces an HMAC-signed grant payload + signature, verified with the Web Crypto crypto.subtle API already available in the Functions runtime carrying the paid tier and an expiry timestamp. The generation endpoint verifies the signature and expiry before touching fal at all — no payment, no fal API call, so a failed or forged request never costs anything. Tier determines both which style presets are unlocked and how many images per style get generated tier.count / tier.styles.length , capped at 12 per style regardless of tier . creativity low and resemblance high — you want it correcting texture, not reinterpreting the image.Live tool: https://dating-photos.pages.dev/ https://dating-photos.pages.dev/ Happy to go deeper on the negative-prompt list or the CF Functions time-limit workaround if useful — drop a comment.