DEV Community

Om Prakash
Om Prakash

Posted on • Originally published at pixelapi.dev

How I Added AI-Generated Headshots to Our Onboarding Flow in an Afternoon

Last month I was building out the user profile section of a SaaS app and ran into the most predictable problem: nobody uploads a decent profile photo. Half our users had the default avatar, a quarter had something blurry shot in bad lighting, and the rest had cropped group photos where you could still see a stranger's shoulder.

I'd seen AI headshot generators as standalone web apps before, but I needed something I could wire into our existing backend — not another product my users had to visit separately. I wanted it to feel like a native feature. That's when I started poking around PixelAPI's AI Headshot endpoint.

Here's what happened when I actually built it.

The actual use case

Our app is a professional directory — think a niche LinkedIn for a specific industry. Profile photos matter. A good headshot signals credibility. We already had an upload flow, but I wanted to add an optional "enhance my photo" step: user uploads a casual selfie, we return a polished headshot-style image.

The requirements I had in mind:

  • Accept a standard image upload from the frontend
  • Return a result fast enough to show inline (no long polling or async job status)
  • Be simple enough that one developer (me) could ship it without a dedicated ML infrastructure project

The sub-3 second latency claim caught my eye. That's synchronous-friendly. If the response comes back in under 3s, I can just await it in the same request handler without building a job queue.

What the integration looks like

The API is a straightforward REST call. You POST an image URL and get back a transformed image URL. Here's the Node.js version of what I ended up shipping:

async function generateHeadshot(sourceImageUrl) {
  const response = await fetch('https://pixelapi.dev/api/v1/ai-headshot', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.PIXELAPI_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      image_url: sourceImageUrl,
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Headshot generation failed: ${error.message}`);
  }

  const data = await response.json();
  return data.output_url;
}

// In your upload handler
app.post('/api/profile/enhance-photo', async (req, res) => {
  const { uploadedImageUrl } = req.body;

  try {
    const headshotUrl = await generateHeadshot(uploadedImageUrl);
    res.json({ headshotUrl });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'Could not generate headshot' });
  }
});
Enter fullscreen mode Exit fullscreen mode

That's genuinely the core of the integration. No SDK to install, no special client library, just fetch. The output URL comes back pointing to a hosted image, so I stored it in our user record the same way we store any uploaded photo URL.

What I got wrong the first time

I initially tried to pass a base64-encoded image directly in the request body instead of a URL. That didn't work — the API expects a publicly accessible URL. My fix was to upload the user's photo to our S3 bucket first, then pass the S3 URL to the headshot endpoint. Two-step, but not complicated.

One thing I'd do differently: I'd add a timeout wrapper around the fetch call. The API is fast, but network conditions vary and you don't want a slow response to hang your entire profile update endpoint.

async function generateHeadshotWithTimeout(sourceImageUrl, timeoutMs = 8000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch('https://pixelapi.dev/api/v1/ai-headshot', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.PIXELAPI_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ image_url: sourceImageUrl }),
      signal: controller.signal,
    });

    clearTimeout(timeoutId);

    if (!response.ok) throw new Error('API error');
    const data = await response.json();
    return data.output_url;
  } catch (err) {
    if (err.name === 'AbortError') throw new Error('Headshot generation timed out');
    throw err;
  }
}
Enter fullscreen mode Exit fullscreen mode

Where else this makes sense

Since shipping this I've thought about a few other places this same endpoint would be useful:

E-commerce seller profiles. Marketplaces where individual sellers have storefronts could offer this as a premium feature — give your store a more professional look without requiring sellers to hire a photographer.

Internal HR tools. Employee directories with consistent, professional-looking headshots. If you're an HR platform and your users are uploading selfies from their phones, you could run those through the API on ingest and standardize the look.

Agency client portals. I talked to a friend who runs a small agency. They build websites for local businesses, and getting usable photos from clients is a constant headache. An automated headshot step in their content intake form would save them a lot of back-and-forth.

Ghost-writing or creator platforms. If you're building something where people have public author profiles, a headshot step in your onboarding reduces friction significantly. Users don't need to have a professional photo ready — they just need any photo.

The thing that actually surprised me

I expected to spend time fiddling with model parameters, aspect ratios, background styles — the usual knobs. There weren't many to fiddle with, which turned out to be a feature. The defaults produce consistent results without me having to tune anything. For a product integration (as opposed to a standalone creative tool), that consistency matters more than flexibility. Every headshot that comes out looks like it belongs in the same visual language.

No card required to get started, so I prototyped the whole thing before committing to anything. That's the right order of operations for evaluating any API you're considering dropping into a production flow.

If you're building anything where user photos matter, it's worth the afternoon to wire this up. The integration surface is minimal and the payoff — users who look like they're taking the product seriously — is real.

Top comments (0)