GLB to USDZ Converter - AR Quick Look Ready (API)
Pricing
from $90.00 / 1,000 conversion successes
GLB to USDZ Converter - AR Quick Look Ready (API)
Convert GLB/glTF to USDZ via API - no Mac, no Xcode. Every file is validated against Apple's ARKit rules and shipped with a QC report: correct PBR materials, Draco/KTX2 support, batch mode, previews, n8n & MCP ready. Fair billing: no valid file, no conversion charge.
Pricing
from $90.00 / 1,000 conversion successes
Rating
5.0
(1)
Developer
Sergey Faraday
Maintained by CommunityActor stats
2
Bookmarked
1
Total users
0
Monthly active users
12 days ago
Last modified
Categories
Share
GLB to USDZ Converter - AR Quick Look Ready
Convert GLB and glTF to USDZ that opens correctly in Apple AR Quick Look - via API, no Mac required. Every file is ARKit-validated and returned with a machine-readable QC report, so what you ship to iPhone, iPad, and visionOS is checked before you pay for it.
Apple has retired its usdzconvert / USDPython tools, and the free browser converters run client-side with no API - a pipeline, a CI job, or an AI agent can't click a browser button. This Actor is the server-side path: URL in, validated .usdz and report out.
Quick start
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~glb-to-usdz/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"source": ["https://example.com/model.glb"]}'
For files that may take over a minute, use the async flow instead - see n8n integration below.
Convert GLB to USDZ in Python - the usdzconvert replacement
Apple's usdzconvert / USDPython toolchain is discontinued, and it only ever ran on macOS. To convert GLB to USDZ in Python now, on any OS, call the Actor with the official client:
from apify_client import ApifyClientclient = ApifyClient("YOUR_TOKEN")run = client.actor("YOUR_USERNAME/glb-to-usdz").call(run_input={"source": ["https://example.com/model.glb"], "textureMaxSize": 2048},)for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["status"], item["arkitCompatible"], item["usdzUrl"])
No Blender scripting, no OpenUSD compilation, no usd_from_gltf build headaches - the USD toolchain runs inside the Actor.
No Mac? No Xcode? No problem
Reality Converter is a macOS GUI app. usdzconvert required a Mac and is now retired. This Actor converts GLB to USDZ on Windows, Linux, CI runners, and serverless pipelines - anywhere you can make an HTTP request. If you've been keeping a Mac mini alive just to produce USDZ files for iOS AR, you can retire it.
Sample report
Each input file produces one dataset row:
{"schemaVersion": "1.0","converterVersion": "1.2.0","source": "https://example.com/model.glb","fileIndex": 0,"status": "ok_with_warnings","arkitCompatible": true,"usdzUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/usdz-abc123.usdz","previewUrl": null,"validation": {"gate": "ARKit ComplianceChecker","gateVersion": "25.11","errors": 0,"warnings": 0},"issues": [],"warnings": [{ "code": "MORPH_STRIPPED", "message": "Morph targets are not supported and were removed." }],"stats": {"inputSizeMB": 4.2,"outputSizeMB": 3.8,"triangles": 12400,"meshes": 3,"materials": 2,"textures": [{ "name": "albedo", "from": "png 4096x4096", "to": "jpeg 2048x2048", "width": 2048, "height": 2048, "files": 1 }],"animations": { "kept": 1, "stripped": 0, "resampled": 1, "skelStripped": 0 },"unitScaleApplied": 1},"timings": {"fetchSec": 0.8,"preprocessSec": 1.2,"convertSec": 3.4,"uploadSec": 0.3,"totalSec": 5.7},"idempotencyKey": "sha256:abc123..."}
status is ok only when the row carries no warnings at all; any warning - even a harmless stripped morph target - makes it ok_with_warnings, and a missing deliverable makes it failed.
Validate an existing USDZ file
Already have a .usdz that "doesn't work in AR"? Run it through the same ARKit compliance checker without converting anything - $0.03 per file:
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~glb-to-usdz/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"mode": "validateOnly", "source": ["https://example.com/model.usdz"]}'
The row comes back with arkitCompatible, the gate's error/warning counts, and every finding as a coded issue. Works for USDZ files produced by any tool, and for .usdz records in your own key-value store (uploadStore + uploadRecords; API names sourceKeyValueStore / sourceKeys still accepted).
Does it keep animations?
Honest answer, because most converters break here:
- Transform animations (translation / rotation / scale clips) - preserved, resampled to LINEAR at 30 fps and exported as USD time samples. Product turntables, hovering objects, opening lids survive.
- Skeletal (rigged) animation - the mesh is converted at a clean bind pose with an explicit
SKEL_STRIPPEDwarning. UsdSkel authoring is on the roadmap; we don't silently ship broken rigs. - Morph targets / blend shapes - not supported by AR Quick Look; stripped with a
MORPH_STRIPPEDwarning, never silently.
Every degradation is a named warning code in the report. You always know what changed.
glTF to USDZ - including multi-file scenes
Multi-file glTF scenes (.gltf + external .bin + textures) are supported: submit them as a zip, or as a .gltf URL whose relative resources resolve automatically. Binary .glb works as-is. Draco- and meshopt-compressed meshes are decoded; KTX2/Basis and WebP textures are transcoded to USDZ-compatible PNG/JPEG with size limits you control.
ARKit validation - because "converted" is not "working"
A .usdz that opens on your desktop can still fail on an iPhone. Every output here runs through Apple's ARKit compliance checker (from OpenUSD) before you're charged for it:
arkitCompatible: true/falseon every file, from the real checker - not a guessfailOn: error | warning | never- you choose whether non-compliant files are deliveredmode: reportOnly- validate the whole conversion pipeline for $0.03 without buying the file
Why your USDZ looks wrong in AR Quick Look
USDZ model appears black or plastic
Metallic-roughness channels must be split into separate grayscale inputs for UsdPreviewSurface; naive converters wire the packed ORM texture straight in and get shiny black plastic. This Actor splits the channels, sets the color space per texture (sRGB for color, raw for data), and folds normalScale / occlusionStrength into the texture network instead of dropping them.
Model is 100× too big (or too small) in AR
glTF is meters; many DCC exports aren't. Rather than silently rescaling your geometry, the report tells you the applied factor and warns on a suspicious scene size (SUSPICIOUS_SCALE). Fix it in one option: targetHeight: 1.5 ("make it 1.5 m tall"), or sourceUnits: "cm" if you know what the DCC exported.
GLB with animation breaks in USDZ
Transform clips are kept; skeletal rigs and morph targets are the parts Quick Look can't play, and they are removed with named warnings instead of producing a frozen or exploded mesh. Set animation: strip if you want a static asset on purpose.
Symptom → cause → where to look
| Symptom | What happened | What to check |
|---|---|---|
| Model invisible or black | Missing or incompatible materials | issues[] for material codes |
| Wrong scale (tiny/huge) | Unit mismatch | stats.unitScaleApplied, try sourceUnits (e.g. "cm") or targetHeight |
| No textures | Source uses KTX2/WebP without extensions | warnings[] for texture codes |
| Transparency broken | Alpha mode incompatibility | Try alphaHandling: forceOpaque |
| Missing animation | Non-transform animation stripped | warnings[] for SKEL_STRIPPED |
| Morph targets gone | Not supported by USDZ/ARKit | warnings[] for MORPH_STRIPPED |
| Dark/flat appearance | Unlit material approximated | warnings[] for UNLIT_APPROXIMATED |
| Sheen/transmission approximated | Mapped onto opacity/roughness (no refraction) | warnings[] for TRANSMISSION_APPROXIMATED / SHEEN_APPROXIMATED |
| Specular strength approximated | Folded into ior (tint averaged) | warnings[] for SPECULAR_APPROXIMATED |
| Anisotropy/iridescence lost | No UsdPreviewSurface equivalent | warnings[] for ANISOTROPY_DROPPED / IRIDESCENCE_DROPPED |
| Wrong orientation / tiling | Coordinate system or texture transform | stats.textures; KHR_texture_transform is authored as UsdTransform2d with the UV flip |
| File won't open in Quick Look at all | Package layout | Packaged through the official USD API (uncompressed, aligned) - check issues[] for gate errors |
| Gate errors on valid model | Strict compliance check | Set failOn: never to deliver anyway |
| File too large | Input exceeds 250 MB limit | Split model or reduce textures |
| SSRF blocked | Private/loopback URL rejected | Use a public URL or KVS input |
Fair billing
A failed conversion never bills conversion-success. Early failures (bad URL, not a GLB, SSRF blocked, too large, empty scene) bill nothing - $0. Actor start is free.
| Path | Price | When |
|---|---|---|
| Conversion success (≤ 50 MB) | $0.12 | USDZ delivered to KV store |
| Large file surcharge (> 50 MB) | +$0.10 | On top of conversion-success |
| Preview render | +$0.02 | outputPreview: true and the PNG was actually delivered |
| Validation report only | $0.03 | reportOnly / validateOnly mode, or failOn-driven USDZ withholding |
| Dedup hit | $0 | Same file+options already converted in this run |
| Early failure | $0 | Fetch/sniff/preprocess error, budget exhausted |
Every output is validated for AR Quick Look using the ARKit ComplianceChecker from OpenUSD.
Output retention
Output URLs are temporary run artifacts - copy the USDZ to permanent storage. The usdzUrl in each report row points to a key-value store record that expires with the run's default retention period. Your models live only in your run's storage under your account; there is no public gallery and no reuse.
MCP / agent integration
This Actor is exposed under the slug glb-to-usdz via Apify's Actor-MCP bridge - callable as a tool from Claude, Cursor, and any MCP client. When calling it as an MCP tool:
- For one model, pass a single-item
sourcearray - Latency is seconds to about a minute per file depending on size and texture count
- On a
status: failedresult, surfaceissues[]to the user - do not blind-retry - Check
arkitCompatibleandwarnings[]before presenting the result as successful - The
usdzUrlis temporary; if the user needs to keep the file, copy it
n8n integration
Use the async chain as the primary recipe - the sync endpoint's ~300 s limit sits at the per-file deadline, so large files on the sync path appear as broken integrations.
- Start run -
POST /v2/acts/YOUR_USERNAME~glb-to-usdz/runswith input JSON - Poll status -
GET /v2/actor-runs/{runId}untilstatusisSUCCEEDEDorFAILED - Get results -
GET /v2/datasets/{defaultDatasetId}/items - Download USDZ -
GETtheusdzUrlfrom each row (no token needed, public URL)
For small files under 1 minute, the synchronous endpoint works:
POST /v2/acts/YOUR_USERNAME~glb-to-usdz/run-sync-get-dataset-items
An n8n workflow template is available at templates/n8n/glb-to-usdz.json. The same recipe fits Make, CI (convert and validate 3D assets on every commit), and e-commerce back ends that generate AR Quick Look assets for every uploaded product model.
Input schema
| Field | Type | Default | Notes |
|---|---|---|---|
uploadedModels | string[] | null | Files dropped into the console's upload widget (.glb / .gltf / .zip); no API needed. Combines with the inputs below |
source | string[] | null | URL(s) to GLB/glTF/ZIP files. Batch up to 200. |
uploadStore | string | null | Apify KVS to read files from, or the store an upload landed in (grants read access to a limited-permission run); combines with source / uploadedModels. Legacy API name sourceKeyValueStore still accepted |
uploadRecords | string[] | null | Record names inside the granted store; optional when the store is only granting access for uploadedModels. Legacy API name sourceKeys still accepted |
mode | convert | reportOnly | validateOnly | convert | reportOnly: full pipeline, report only, no USDZ ($0.03). validateOnly: validate an existing .usdz (URL or KVS record), no conversion ($0.03) |
textureMaxSize | integer 256-4096 | 2048 | Max texture dimension (longest side); 1024 / 2048 / 4096 are the useful stops |
textureFormat | auto | png | jpeg | auto | Color textures only; data textures always PNG |
unitScale | auto | asIs | number | auto | Meters-per-unit scale factor |
sourceUnits | mm | cm | m | inches | feet | null | Units the model was authored in; resolves to the numeric scale for you. targetHeight takes precedence if both are set (SCALE_OPTION_OVERRIDDEN warning) |
targetHeight | number | null | Desired model height (in targetHeightUnit, meters by default); the converter measures the bounding box and computes the scale. Wins over sourceUnits and numeric unitScale (SCALE_OPTION_OVERRIDDEN warning) |
targetHeightUnit | m | cm | mm | inches | feet | m | Unit of targetHeight; converted to meters before processing, so 150 cm and 1.5 m are the same job |
animation | preserve | strip | preserve | Transform animations only |
alphaHandling | preserve | forceOpaque | preserve | Force opaque discards alpha |
failOn | error | warning | never | error | Controls USDZ delivery on gate findings |
outputPreview | boolean | false | Render a flat 800×800 transparent PNG preview alongside the USDZ (+$0.02). A failed render never blocks the USDZ |
targetMaxFileSizeMB | number | null | Warn (TARGET_SIZE_EXCEEDED) when the output USDZ exceeds this size; failOn decides delivery |
webhookUrl | string | null | POST the batch summary to this URL when the run completes |
Getting the size right in AR
Three user-friendly ways to fix a model that shows up tiny or huge in Quick Look, in order of preference:
targetHeight: 1.5- "make it 1.5 m tall". No unit archaeology needed.sourceUnits: "cm"- you know the DCC exported centimeters.unitScale: 0.01- the raw numeric factor, for scripts that computed it themselves.
Quick Look's AR texture budget: keep textures ≤ 2048×2048 and ≤ 6 total. The report warns with AR_TEXTURE_BUDGET_WARNING when the output exceeds Apple's recommendation.
Quick Look embedding tip
Lighting in AR Quick Look is controlled on the embed side, not inside the USDZ. When linking a USDZ on the web, you can pin the newer image-based lighting for glossier, more accurate materials:
<a rel="ar" href="model.usdz#preferredIblVersion=2">View in AR</a>
FAQ
How do I convert GLB to USDZ without a Mac? Call this Actor from any OS via HTTP (or the Python client above) - the USD toolchain runs server-side. No Reality Converter, no Xcode, no macOS.
Is Apple's usdzconvert still available? No - Apple has retired its Python USDZ tools. This Actor is a maintained server-side replacement with ARKit validation on top.
Does GLB to USDZ conversion keep animations? Transform animations, yes. Skeletal rigs are converted at bind pose with a warning; morph targets aren't supported by AR Quick Look and are stripped with a warning.
What does "ARKit validated" mean?
Every file runs through Apple's ARKit compliance checker inside the Actor. The report says arkitCompatible: true only when the checker finds zero errors - that is what makes the file safe for iOS, iPadOS, and visionOS Quick Look.
Can I check a USDZ I already have?
Yes - mode: validateOnly runs the same gate on an existing .usdz for $0.03, no conversion.
Are my models stored? Only in your run's Apify storage, under your account's retention settings. There is no public gallery and no reuse of your models.
Current limits and roadmap
Skeletal (UsdSkel) animation authoring, FBX/OBJ/STL inputs, and USDZ→GLB reverse conversion are not in this version - they are tracked publicly on the roadmap. Previews, validation of existing USDZ files, and multi-file glTF input are already here.
