TRY-ON
BlogGeneral
Build an AI Ring Try-On App with Claude Code, the YouCam API and MCP
AR Accessories

Build an AI Ring Try-On App with Claude Code, the YouCam API and MCP

author Author: Chia-Lin
Nov 11, 2026 · 20 minutes read
yt
linkedin_share
facebook_share
twitter_share
email_share
Build an AI Ring Try-On App with Claude Code, the YouCam API and MCP
yt
linkedin_share
facebook_share
twitter_share
email_share

Ring virtual try-on has a reputation among developers for being the hard one. Makeup sits on a face that a detector can find reliably. Clothes drape over a body with a well understood silhouette. A ring has to land on one specific finger, at one specific point along that finger, oriented correctly, lit to match the hand it is sitting on, and partially hidden where the finger curls in front of it. Get any of those wrong and the result does not look slightly off, it looks fake.


The useful news is that none of that has to be your problem. The YouCam AR Ring Virtual Try-On API takes a flat product photograph of a ring and a photograph of a hand and returns a composited image, with finger selection, placement, shadow and ambient light exposed as parameters you control. No 3D model, no asset pipeline, no rigging. This walkthrough builds a working try-on app against it, driven from Claude Code through the YouCam MCP server, and spends most of its time on the parameters that decide whether the output is convincing.

What You Are Building

A web app where a user uploads a photograph of their hand, picks a ring from a catalogue, and sees it rendered on the finger of their choice with adjustable placement. The pieces:

LayerWhat it doesWhat provides it
CatalogueRing product images, three-quarter front viewYour own data. Flat 2D photographs, no 3D assets
UploadGets the hand image and ring image into the serviceTwo step file API, or a public image URL
CompositePlaces, orients, lights and occludes the ringThe ring try-on task endpoint
ControlsFinger, position along the finger, shadow, ambient lightTask parameters, exposed in your UI
DeliveryReturns a rendered image to the browserTask polling, then a signed result URL

Claude Code writes almost all of the glue. What it cannot do is composite the ring, which is the point worth internalising before starting: a language model can build the entire application around an image operation it has no ability to perform.

What You Need Before You Start

RequirementDetail
API keyFree from the YouCam API Console, with free units for testing
Ring imagesThree-quarter front view, roughly 45 degrees. JPG, JPEG or PNG
Hand imagesBack of the hand fully visible, all five fingers clear, nothing occluding them
Image limitsLong side 4096px or less, under 10MB per file
RuntimeAnything that can make HTTPS requests. Examples exist for Node, Python, PHP, Java, Flutter and cURL
Claude CodeOptional but assumed here, with the YouCam MCP server connected

The two image requirements are not suggestions. A ring photographed straight on has no visible band curvature for the engine to align, and a hand with fingers overlapping gives it nothing to place against. More integration time is lost to source imagery than to code.

Connecting Claude Code to the YouCam MCP Server

The MCP server lets Claude call YouCam features directly while it is writing your app, which means you can test a composite before any of your own code exists. Fashion and accessory features live on the fashion server.

claude mcp add youcam-fashion \
  -- npx -y mcp-remote https://mcp-api-01.makeupar.com/mcp/fashion \
  --header "Authorization: Bearer YOUR_API_KEY"

With that connected, you can hand Claude a ring image and a hand image and ask for a try-on directly in the conversation. The value is not the shortcut, it is that you see a real output before committing to an interface, and you find out immediately whether your product photography is usable. If you prefer working outside an editor entirely, the YouCam CLI reaches the same endpoints from a terminal, and YouCam API Agent Skills cover the agent side.

The Integration Flow

Three calls, against base URL https://yce-api-01.makeupar.com, with a bearer token on every request.

1. Register and upload the files

File upload is two steps rather than a multipart post. You declare the files first and receive a signed destination for each.

POST /s2s/v2.0/file/2d-vto/ring
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "files": [
    { "content_type": "image/jpeg", "file_name": "hand.jpg", "file_size": 842134 },
    { "content_type": "image/png",  "file_name": "ring.png", "file_size": 211904 }
  ]
}

The response returns a file_id per file plus the upload request details, including the URL, method and headers to use. Upload each file to its own destination, then carry the file_id values into the task. If your catalogue images are already on a public CDN you can skip this entirely and pass URLs instead, which is usually the right call for the ring side and the wrong call for the hand side, since user uploads are rarely public.

2. Create the try-on task

POST /s2s/v2.0/task/2d-vto/ring
Authorization: Bearer YOUR_API_KEY

{
  "source_info": {
    "src_file_id": "HAND_FILE_ID"
  },
  "object_infos": [
    {
      "name": "ring_1",
      "ref_file_id": "RING_FILE_ID",
      "parameter": {
        "ring_wearing_finger": 3,
        "ring_wearing_location": 0.45,
        "ring_shadow_intensity": 0.15,
        "ring_ambient_light_intensity": 1.0,
        "ring_need_remove_background": true
      }
    }
  ]
}

Source and reference inputs accept file ids or URLs and the two can be mixed, so a CDN hosted ring and an uploaded hand in the same request is a normal shape.

3. Poll for the result

GET /s2s/v2.0/task/2d-vto/ring/{task_id}
Authorization: Bearer YOUR_API_KEY

Poll roughly every ten seconds until task_status is success or error. On success the response carries a result URL. Webhooks are the better pattern where your stack supports them, because polling a composite that a user is waiting on is exactly the case where webhooks earn their complexity.

LifetimeValueWhat it means for your app
task_id24 hoursYou can re-poll a task long after the request, but do not treat it as storage
Result URL2 hoursDownload and persist it yourself if the user needs it again. Do not store the signed URL

That second row catches people. A signed URL saved into a database works perfectly in testing and starts returning errors in production two hours later. Fetch the bytes, store them somewhere you own, and serve your own URL.

The Parameters That Decide Whether It Looks Real

This is the part worth slowing down for. The endpoint is simple. The difference between a convincing try-on and an obvious paste job lives entirely in these five values.

ParameterRangeDefaultWhat it controls
ring_wearing_finger0 to 4Engine default0 thumb, 1 index, 2 middle, 3 ring, 4 little finger
ring_wearing_location0.0 to 1.0Engine defaultPosition along the finger, from the base knuckle toward the middle joint
ring_shadow_intensity0.0 to 1.00.15How strongly the ring casts a shadow onto the finger
ring_ambient_light_intensity0.0 to 1.01.00 ignores the hand's lighting, 1 fully matches it
ring_need_remove_backgroundBooleantrueAutomatic background removal on the ring image

Expose the finger, not just the ring

Most ring try-on interfaces let the user pick a ring and nothing else. That is a mistake, and an easy one to avoid since the parameter already exists. People wear rings on different fingers for different reasons, and an engagement ring rendered onto an index finger is not the experience anyone came for. Make finger selection a visible control with a sensible default rather than a hard coded 3.

Position matters more than it sounds

ring_wearing_location runs from the base of the finger toward the first joint. A wedding band sits low. A statement cocktail ring usually sits higher. A stacking set needs each ring at a different value or they render on top of each other. If you are selling more than one category, store a default location per product rather than using one value for the catalogue.

Ambient light is the realism dial

At 1.0 the ring picks up the lighting and shadows of the hand it is sitting on, which is almost always what you want. Lower values make the ring look lit independently of the scene, which reads as a sticker. The reason to ever reduce it is a hand photograph with extreme or coloured lighting, where full matching tints the metal in a way that misrepresents the product. That is a merchandising decision and worth surfacing to whoever owns the catalogue, not burying in a config file.

Shadow is the one to leave alone

The 0.15 default is conservative and generally correct. Raising it looks dramatic in a single hero image and wrong across a varied catalogue of hand photographs, because the shadow no longer agrees with the light in the scene. Change it only with a specific image in front of you.

Two Advanced Controls Worth Knowing About

ControlWhen you need it
Occlusion masksOptional masks for the hand or the ring, supplied alongside the images, to fine tune segmentation. Reach for these when a specific product repeatedly renders with the wrong edge in front
ring_anchor_pointTwo pixel coordinates marking the inner edge contact points of the ring. Useful for wide or unusually thick bands where automatic detection is slightly off. Omit it and the engine detects them

Both are escape hatches rather than defaults. Ship without them, identify the handful of catalogue items that look wrong, and apply them per product. Setting anchor points for an entire catalogue up front is a large amount of work to solve a problem you may not have.

Stacking Multiple Rings

Stacking is one of the stronger commercial cases for this API, and it is handled by the shape of the request rather than by a separate endpoint. object_infos is an array, so you add an entry per ring, each with its own name, reference image and parameters. Add the hand once.

"object_infos": [
  { "name": "band",      "ref_file_id": "A", "parameter": { "ring_wearing_finger": 3, "ring_wearing_location": 0.30 } },
  { "name": "solitaire", "ref_file_id": "B", "parameter": { "ring_wearing_finger": 3, "ring_wearing_location": 0.55 } },
  { "name": "midi",      "ref_file_id": "C", "parameter": { "ring_wearing_finger": 1, "ring_wearing_location": 0.80 } }
]

Give each one a distinct ring_wearing_location. Two rings at the same value on the same finger will fight for the same pixels, and the result looks exactly as broken as it sounds. A stacking builder that enforces minimum spacing between entries is a small amount of front end work that prevents most bad output.

What Claude Code Can and Cannot Do Here

Worth being precise about, because the split is instructive.

TaskClaude Code
Upload flow, polling, retries, error handlingWrites it well. This is ordinary API plumbing
Catalogue UI, finger picker, stacking builderWrites it well, and iterates on it quickly
Storing results, signed URL expiry handlingWrites it well once you tell it the two hour limit
Choosing sensible default locations per product typeReasonable suggestions, but verify against real output
Compositing the ring onto the handCannot do this at all. This is what the API is for
Judging whether the output looks convincingCannot do this reliably. A human has to look

The last two rows are the ones that matter. An agent can build the entire product around an operation it cannot perform, which is a reasonable description of what most AI application development now looks like.

Testing Before You Ship

Four things, none of which take long and all of which are routinely skipped.

Test every finger. Hand geometry varies and the little finger is the one most likely to expose placement problems.

Test across skin tones. Segmentation and ambient light matching both behave differently across a range, and a catalogue that only ever rendered onto the development team's hands is not tested.

Test your worst product photograph. Not your best one. The straight on shot, the one on a reflective surface, the one with a shadow across the band. Those are the items that will generate support tickets.

Test expiry. Deliberately hold a result URL for over two hours and confirm your app handles it. This is the single most common production bug in polling based image APIs.

The ring try-on playground is the fastest way to run these checks before writing any code, and the API documentation carries the full field definitions.

Why Rings Are a Good First Try-On Build

They are commercially well suited to virtual try-on in a way that is not true of every category. Jewellery has a high average order value, a high return rate driven by uncertainty, and almost no ability to try before buying online. A ring is also a small, well defined object, which keeps the composite tractable.

If you are weighing which category to build first, the AI jewelry API overview covers the commercial case, and virtual ring try-on use cases covers where it tends to be deployed.

FAQ

Do I need 3D models of my rings?

No. Flat 2D product photographs are sufficient, which is the main practical advantage over traditional AR jewellery pipelines. A three-quarter front view at roughly 45 degrees is what the engine expects.

Which fingers are supported?

All five. ring_wearing_finger takes 0 through 4, mapping to thumb, index, middle, ring and little finger.

Can I place more than one ring?

Yes. object_infos is an array and each entry carries its own ring image and parameters. Give each one a different ring_wearing_location so they do not overlap.

What image sizes does it accept?

JPG, JPEG or PNG, long side 4096px or less, under 10MB per file. The hand needs all five fingers visible and unobscured.

How long are results available?

The task id stays valid for 24 hours and the result URL for 2 hours. Download and store the image yourself if the user needs it later.

Should I poll or use webhooks?

Webhooks where your stack supports them. Polling roughly every ten seconds is the documented fallback and is fine for a prototype, but a user staring at a spinner is the case webhooks exist for.

Do I have to use Claude Code or MCP?

No. It is a standard RESTful API with bearer authentication and examples in JavaScript, Java, Flutter, Python, PHP, Node and cURL. MCP is a convenience for building, not a dependency at runtime.

What usually goes wrong first?

Source imagery, by a wide margin. Rings photographed straight on, hands with overlapping fingers, and product shots with a background the removal step struggles with. Fix the images before debugging the integration.

Conclusion

The hard parts of ring try-on, placing a small object on a specific finger with correct orientation, lighting and occlusion, are the parts you do not write. What is left is an upload flow, a polling loop and a handful of parameters, which an agent can assemble in an afternoon.

Spend the time you save on the two things that actually determine quality: product photography that meets the input requirements, and sensible default placements per product category. Those decisions are worth more to the finished experience than any amount of integration code.

Get a free API key and run your worst ring photograph through the playground first, or talk to our team about catalogue scale deployment.


yt
linkedin_share
facebook_share
twitter_share
email_share