🗓️ Everything *[NYC] is back. A free gathering for AI builders. Sept 9 →

How to programmatically set image field from another image's URL in Sanity?

10 repliesLast updated: Dec 2, 2025

Hi. I have two image fields. When the first is populated, I want to take its asset.url, create something in a canvas and add the dataUrl into the other image field. Is this a job for a plugin, or a custom input component, or is there some simpler way? Thanks.
AI Update

A custom input component is definitely the right approach for your use case! Since you need to work with two related image fields (one original and one transformed), you'll want to create a custom input component that manages both.

Here's how to set it up based on the Custom Input Components documentation:

Schema Setup

First, create an object type with both image fields:

import {defineField, defineType} from 'sanity'

export default defineType({
  name: 'transformedImage',
  type: 'object',
  fields: [
    defineField({
      name: 'original',
      type: 'image',
      title: 'Original Image'
    }),
    defineField({
      name: 'transformed',
      type: 'image',
      title: 'Transformed Image'
    })
  ],
  components: {
    input: MyCustomImageTransform  // Your custom component
  }
})

Custom Input Component

Then build your custom input component:

import {useCallback} from 'react'
import {Stack, Card} from '@sanity/ui'
import {set, unset} from 'sanity'

function MyCustomImageTransform(props) {
  const {value, onChange, renderDefault} = props
  
  const handleOriginalUpload = useCallback(async (originalAsset) => {
    if (!originalAsset) return
    
    // 1. Get the asset URL
    const imageUrl = originalAsset.asset.url
    
    // 2. Create your canvas and do your transformation
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    // ... your canvas transformation logic here ...
    
    // 3. Convert canvas to blob
    const blob = await new Promise(resolve => 
      canvas.toBlob(resolve, 'image/png')
    )
    
    // 4. Upload the blob as a new asset using the Sanity client
    const transformedAsset = await props.client.assets.upload('image', blob, {
      filename: 'transformed.png'
    })
    
    // 5. Update both fields using onChange
    onChange([
      set({
        original: originalAsset,
        transformed: {
          _type: 'image',
          asset: {
            _type: 'reference',
            _ref: transformedAsset._id
          }
        }
      })
    ])
  }, [onChange, props.client])
  
  // Render the default input but intercept changes
  return (
    <Stack space={3}>
      {renderDefault({
        ...props,
        // Override the onChange to intercept original image uploads
        onChange: (patchEvent) => {
          const patches = patchEvent.patches
          const originalPatch = patches.find(p => p.path?.[0] === 'original')
          
          if (originalPatch?.value) {
            handleOriginalUpload(originalPatch.value)
          } else {
            onChange(patchEvent)
          }
        }
      })}
    </Stack>
  )
}

Key Points

This approach keeps everything within Sanity's asset management system and gives you full control over the transformation workflow!

Show original thread
10 replies

Was this answer helpful?

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Related contributions