Fixing Image Problems in JSON-LD
Images in structured data are what search features use for thumbnails, product photos, recipe cards and organisation logos. When the markup gives a relative path, an address that redirects to a login page, a file blocked by robots.txt or a picture too small to use, the image is dropped and the result can lose its visual or its eligibility.
None of this shows on the page itself. This guide covers how to write image values correctly, how to test each file the way a crawler fetches it, the size and ratio guidance that applies, and platform quirks that produce bad image URLs.
Three correct ways to write an image
The image property accepts a URL, a list of URLs, or an ImageObject. All
three are valid, and Google's features accept each of them. A common myth, repeated in older guides,
is that a plain URL "does not count" and that width and height are compulsory. They are not required
for Google's features, though they are useful information when you have them.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Recipe",
"name": "Rhubarb and Ginger Crumble",
"image": [
"https://www.example.co.uk/images/crumble-16x9.jpg",
"https://www.example.co.uk/images/crumble-4x3.jpg",
"https://www.example.co.uk/images/crumble-1x1.jpg"
],
"author": { "@type": "Person", "name": "Morgan Vale" },
"publisher": {
"@type": "Organization",
"name": "Fernhill Kitchen",
"logo": {
"@type": "ImageObject",
"url": "https://www.example.co.uk/images/fernhill-logo-600x600.png",
"width": 600,
"height": 600
}
}
}
</script>
- A single URL is the simplest and is fine when you only have one image.
- A list of URLs lets you offer different crops, so a feature can choose the ratio that fits its layout.
- An ImageObject lets you add
width,height,caption,creditTextorlicense. If you give dimensions, they must match the real file; wrong numbers are worse than none.
A different property, thumbnailUrl, is used by VideoObject and is required there. logo
on an Organization is its own property with its own guidance, covered below.
The image findings you will meet
| What the markup contains | Why it fails | Fix |
|---|---|---|
/images/photo.jpg | A relative path. JSON-LD values are not resolved against
the page address the way an HTML src is. | Write the full address including https://
and the host. |
//cdn.example.co.uk/photo.jpg | Protocol-relative. Some consumers cannot resolve it and validators flag it. | Prefix https:. |
http://www.example.co.uk/photo.jpg | Plain http on an https site; it usually redirects, and some consumers do not follow it or treat it as a different file. | Use the final https address. |
| An address that returns 404, 403 or a login page | The image cannot be fetched, so it is ignored. | Point at a file that returns 200 to anonymous requests. |
| A page URL rather than a file, such as an attachment page | The address returns HTML, not an image. | Use the direct file address ending in the image itself. |
data:image/png;base64,... | An embedded data URI has no address to crawl or index. | Host the image as a file and link to it. |
A lazy-loading placeholder, such as blank.gif or a tiny blurred preview | The
template read the placeholder src instead of the real image. | Read the original image field, not the attribute the lazy loader rewrites. |
An empty string or null | No image was set for this item. | Leave the property out, or add a real image to the content. |
Can a crawler actually fetch the file?
An address that opens in your browser is not proof that a crawler can fetch it. Your browser has cookies, a logged-in session and a familiar user agent; a crawler has none of these. Three checks cover almost every case.
1. robots.txt
Search engines will not fetch images from paths your robots.txt disallows. Older WordPress setups
sometimes block /wp-content/ or /wp-includes/, and some sites block a /cdn/
or /media/ folder to save crawl budget. If the image host is a separate subdomain or CDN,
it has its own robots.txt that needs checking too.
2. The HTTP response
Request the image without any cookies and look at the status and content type:
curl -sI -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
https://www.example.co.uk/images/crumble-16x9.jpg
You want HTTP/2 200 (or HTTP/1.1 200) and a content-type beginning
with image/. A 301 or 302 is tolerable if it ends at a 200 image, but it is better to link
the final address directly. A 403 often means hotlink protection or a firewall rule is refusing requests
without a matching referrer or with an unfamiliar user agent. Note that pretending to be Googlebot with
curl is only a rough test: some firewalls verify real Googlebot by IP address and behave differently,
so confirm with URL Inspection.
3. URL Inspection
In Search Console, inspect the page, choose Test live URL and open the page resources list. Images that Google could not load are listed there with a reason. This is the most reliable test because it uses Google's own fetcher from Google's own addresses.
Size, ratio and format guidance
Google publishes image guidance per feature rather than one rule for all. The points below are from its documentation at the time of writing; check the relevant feature page if a result behaves unexpectedly.
| Where the image is used | Guidance |
|---|---|
| Article and similar content images | High-resolution images of at least 50,000 pixels when width is multiplied by height, ideally offered in 16:9, 4:3 and 1:1 ratios. |
| Recipe | image is required, and Google asks for images of the finished dish
in the same range of ratios. |
Organization logo | At least 112 by 112 pixels, in a format Google Images supports, and legible on a white background. |
| Product (merchant listings) | image is required; use real photos of the product
rather than a placeholder or a logo. |
| VideoObject | thumbnailUrl is required and must point at a crawlable image. |
As a working rule, a 1200 pixel wide image comfortably clears the Article threshold at every common ratio: 1200 by 675 is 810,000 pixels. The images that fail are usually thumbnails, such as a 150 by 150 crop that a theme generates for archive listings and then reuses in the markup. JPEG, PNG, WebP and GIF are safe formats. Keep the file size sensible, but do not compress it to the point where the picture is blurred or blocky.
Which picture, not just which file
The image should represent the thing the markup describes. An article image should belong to that
article; a product image should show that product. A site-wide logo or a generic banner used as the image
of every post passes a format check but is not what the feature expects, and it gives every result the
same thumbnail. A logo belongs in logo or the publisher, not in the content's image.
Platform quirks that produce bad image URLs
WordPress
SEO plugins usually take the featured image and fall back to a default image set in their settings.
Two problems are common: posts with no featured image get the site logo as their image, and the plugin
picks a small registered size rather than the full file. Set a featured image on every post that carries
Article or Recipe markup, and check the plugin's default image setting. If you build markup yourself,
wp_get_attachment_image_url( $id, 'full' ) returns the full-size absolute address.
Shopify
The Liquid image_url filter returns an address that begins with //, with
no protocol. In a JSON-LD snippet, write {{ product.featured_image | image_url: width: 1200 | prepend: 'https:' | json }}
so the result is absolute and correctly quoted. Choose a width large enough for the feature; the theme's
own card width is often too small.
Static sites and custom builds
Templates frequently hold image paths relative to the site root because that is what HTML needs. Join
them with a configured base address when writing JSON-LD, and make sure the base is the production host,
not localhost or a staging domain left over from development.
Image CDNs and optimisers
Framework and CDN image optimisers serve resized files from generated addresses, often with query strings describing width and quality. These can work, but they are fragile if the parameters change or the optimiser refuses unknown requests. Pointing the markup at the original stored image, or a stable CDN address for it, is safer.
The fix, step by step
Step 1
List every image URL in the markup
Run
a page from each template through the JSON Checker and copy out every value of image, logo,
thumbnailUrl and any ImageObject url, contentUrl or thumbnail.
Include the blocks printed by plugins, apps and the theme, not only your own. Mark any value that is
empty, relative, protocol-relative, plain http or an embedded data URI, because those can be fixed before
you test a single file.
Step 2
Make each URL absolute and https
Change
the template so every image address is written in full, starting with https:// and the production
host. In Liquid add prepend: 'https:' after image_url; in custom code join
root-relative paths with a configured base address. Replace any http address with its final https version
and remove redirect hops, so the value in the markup is exactly the address that returns the image.
Step 3
Request each image as a crawler would
Fetch each address with curl -sI and no cookies, and confirm a 200 status with
an image/ content type. Check robots.txt on the image host for disallowed folders, and look
for firewall or hotlink rules that refuse requests without a referrer. Then run URL Inspection with a
live test in Search Console and check the page resources list for images Google could not load.
Step 4
Check size and aspect ratio
Open
each image and note its real pixel dimensions. For article and recipe images, confirm width multiplied
by height is at least 50,000 pixels and offer 16:9, 4:3 and 1:1 crops where you can. Check logos are
at least 112 by 112 pixels and readable on white. If an ImageObject states width and height,
correct them to the real values or remove them.
Step 5
Point the markup at the right picture
Make
sure each image represents the thing being described: the article's own picture, a photo of the product,
the finished dish. Replace site-wide logos or banners used as content images, and move the logo into
logo or the publisher. Where a template picks a small thumbnail size or a lazy-load placeholder,
change it to read the full original image field instead.
Step 6
Retest and confirm in Search Console
Re-run the JSON Checker and the Rich Results Test on one URL per template and confirm the images are detected without warnings. Use Validate fix on any enhancement report that listed image errors, such as Product or Recipe. Keep a note of the image host, robots.txt rules and firewall settings you checked, because a CDN or security change later can quietly break the same images again.
Edge cases
- Images on a different domain. Allowed, as long as the host lets crawlers fetch them. Check that host's robots.txt, not only your own.
- Query strings. An address such as
photo.jpg?v=3is fine. Avoid strings that change on every build, because each change looks like a new image to a crawler. - Transparent PNG logos. A white logo on a transparent background disappears on the white backgrounds where logos are often shown. Supply a version that reads on white.
- Images that change with stock or variant. Make sure the markup and the visible page show the same image for the selected variant, or use the main product image in both.
- Very large originals. A 9,000 pixel camera original is valid, but slow to fetch. A 1,200 to 2,000 pixel version is a sensible middle ground.
Images in structured data are only one side of image quality. For the visible images on the page, the image size guide covers file weight and loading speed.
1. Does the image in JSON-LD have to be an ImageObject?
No. The image property accepts a plain URL, a list of URLs or an ImageObject, and Google features accept all three. An ImageObject is useful when you want to add dimensions, a caption, a credit or licence details, but it is not required for eligibility. If you do include width and height, make sure they match the real file, because incorrect dimensions give consumers wrong information and are worse than leaving the numbers out.
2. Why is my image flagged when it opens fine in my browser?
Your browser is not a crawler. It carries cookies, may be logged in, sends a referrer and uses a familiar user agent, all of which can let it past rules that block anonymous requests. A crawler has none of those. Check robots.txt on the image host, request the file with curl and no cookies, and run a live URL Inspection in Search Console to see whether Google itself could load it.
3. How big should a structured data image be?
For article and recipe images Google asks for high-resolution pictures of at least 50,000 pixels when width is multiplied by height, ideally in 16:9, 4:3 and 1:1 ratios. A 1200 pixel wide image clears that easily. Organisation logos need to be at least 112 by 112 pixels. Problems usually come from templates that reuse a small archive thumbnail, so check which image size your theme or plugin actually outputs in the markup.
4. Can I use my logo as the image for every blog post?
You can write it, and it will pass a format check, but it is not what the feature expects. The image should represent the specific article, product or recipe being described, so a shared logo gives every result the same unhelpful thumbnail and may be ignored. Put the logo in the publisher or Organization logo property, and give each post its own featured image that actually belongs to that particular piece of content.
5. Do relative image URLs work in JSON-LD?
Not reliably. In HTML a browser resolves a relative src against the page address, but values inside JSON-LD are plain text and consumers may not resolve them the same way, so a path such as slash images slash photo dot jpg is often treated as invalid. Always write the full address with https and the host name. Protocol-relative addresses that start with two slashes should also be given an explicit https prefix.
6. Can I use WebP or AVIF images in structured data?
WebP is widely supported by search engines and is a safe choice alongside JPEG, PNG and GIF. Support for newer formats varies by consumer, and not every platform that reads structured data will display them, so if you serve AVIF on the page it is sensible to point the markup at a JPEG or WebP version of the same picture. Whatever the format, the file must be crawlable and return an image content type.
7. Why did my images break after moving to a CDN?
CDNs often add hotlink protection, bot filtering or signed URLs, any of which can refuse crawler requests while your own browser still loads the files. Moving to a new host can also change image addresses, leaving old ones in the markup that now redirect or return errors. Check the new host robots.txt and firewall rules, confirm with a live URL Inspection, and update the template so markup uses the new stable addresses.
The JSON Checker parses every JSON-LD block on your page, validates the syntax, checks each type against schema.org, verifies required fields, detects conflicting types and runs the result against Google rich result criteria.
Open JSON-LD Fixes โ