# Photoshop batchPlay write XMPMetadata works for document but not layer

**URL:** <https://forums.creativeclouddeveloper.com/t/photoshop-batchplay-write-xmpmetadata-works-for-document-but-not-layer/12393>\
**Category:** UXP Plugin API\
**Created:** [October 30, 2026, 9:35pm UTC](https://forums.creativeclouddeveloper.com/t/photoshop-batchplay-write-xmpmetadata-works-for-document-but-not-layer/12393 "2026-10-30T21:35:00Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![markbargen](https://avatars.discourse-cdn.com/v4/letter/m/c57346/32.png) [@markbargen](https://forums.creativeclouddeveloper.com/u/markbargen)\
**Post date:** [October 30, 2026, 9:35pm UTC](https://forums.creativeclouddeveloper.com/t/photoshop-batchplay-write-xmpmetadata-works-for-document-but-not-layer/12393/1 "2026-10-30T21:35:01Z")

</div>

I will be grateful for any suggestions or corrections!

What works: using batchPlay, I can successfully read, update, and then write XMPMetadata for the current document, and subsequently read it back and my updates are present.

After reviewing posts by Simon Henke and Rob, I would anticipate that I could make a similar scenario work for layer metadata.

> [@Photoshop UXP plugin + XMPMetadata](https://forums.creativeclouddeveloper.com/t/photoshop-uxp-plugin-xmpmetadata/2166/2):
>
> There’s no API yet. You can set this kind of metadata via AM code, or now with BatchPlay, however it can get quite complicated. During prerelease I’ve build a setup for me that works for settings/getting/resetting metadata to/from layers. It’s far from perfect though, I’m neglecting the full XMP structure or syntax like you’d see in the document metadata. It works for me, as the layers don’t have any metadata by default. There are some flaws, for example I heard that it won’t keep the metadata…

> [@XMP Metadata Access Completely Broken in Photoshop 27 - Critical Regression for UXP Plugin Developers](https://forums.creativeclouddeveloper.com/t/xmp-metadata-access-completely-broken-in-photoshop-27-critical-regression-for-uxp-plugin-developers/11544):
>
> Summary After upgrading from Photoshop 26 to 27, all XMP metadata read/write operations in UXP plugins have stopped working. This appears to be an undocumented breaking change that affects any plugin using XMP metadata functionality. Background I maintain several UXP plugins that rely heavily on XMP metadata for storing application data within Photoshop documents. These plugins worked flawlessly in PS 26 and earlier versions. I also recently published “The Definitive Guide to UXP XMP In…

The scenario that does not work (code and results below):

- I can read the metadata (using batchPlay) for the current layer and create a XMPMeta object. The serialized result appears to be valid, with an empty \<`rdf:Description/`\> element positioned in the DOM at the same location as it appears in the corresponding serialized document XMPMeta.
- I can append an array item. The serialized XMPMeta object now includes the appended array item.
- I can write the metadata (using batchPlay). The batchPlay return value is an array of one element, which is an empty object `[{}]`. There is no indication of anything other than success.
- If I then re-read the metadata and create a new XMPMeta object(same code as before), the serialized result is the same as before, that is, lacking the appended array item.

The code I am using:

Code to read the layer metadata and inspect it:

```auto
const { action, app, core } = require("photoshop");
const { XMPMeta, XMPConst } = require("uxp").xmp;

function getLayerXMP() {
    return action.batchPlay(
        [
            {
                _obj: "get",
                _target: {
                    _ref: [
                        { _property: "XMPMetadataAsUTF8" },
                        { _ref: "layer", _enum: "ordinal", _value: "targetEnum" },
                    ],
                },
            },
        ],
        { synchronousExecution: true }
    );
};

let xmpData = getLayerXMP();
let meta = new XMPMeta(xmpData);
let serialized = meta.serialize();

```

The resulting serialized value (omitting numerous blank lines after the last closing tag)

```auto

<?xpacket begin="﻿" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 10.0-c000 79.4332aae, 2026/08/17-13:39:43 ">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description rdf:about=""/>
  </rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>

```

Code to append an array item and inspect the updated metadata:

```auto
meta.appendArrayItem(XMPConst.NS_DC, "description", "Set description Here", 0, XMPConst.ARRAY_IS_ALTERNATIVE);
let serialized = meta.serialize();

```

The resulting serialized value (again, omitting numerous blank lines)

```auto
<?xpacket begin="﻿" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 10.0-c000 79.4332aae, 2026/08/17-13:39:43 ">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description rdf:about=""
        xmlns:dc="http://purl.org/dc/elements/1.1/">
      <dc:description>
        <rdf:Alt>
          <rdf:li>Set description Here</rdf:li>
        </rdf:Alt>
      </dc:description>
    </rdf:Description>
  </rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>

```

The code to write the metadata:

```auto
async function setLayerXMP(xmpString) {
    try {
        return await core.executeAsModal(
            async () => {
                return await action.batchPlay(
                    [
                        {
                            _obj: "set",
                            _target: [
                                { _property: "XMPMetadataAsUTF8" },
                                { _ref: "layer", _enum: "ordinal", _value: "targetEnum" },
                            ],
                            to: {
                                _obj: "XMPMetadataAsUTF8",
                                XMPMetadataAsUTF8: xmpString,
                            },
                        },
                    ],
                    { synchronousExecution: false });
            }, { commandName: "Setting XMP..." });
    } catch (error) {
        console.error(error);
    }
};
let result = await setLayerXMP(meta.serialize());

```

The (stringified) return value:

```auto
[{}]

```

If anyone can make any suggestions, or tell me where I’m hgoing wrong, please do!  
Thanks

---

<div class="post-metadata">

**Author:** ![Jarda](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/jarda/32/1909_2.png) [@Jarda](https://forums.creativeclouddeveloper.com/u/Jarda)\
**Post date:** [October 30, 2026, 11:32pm UTC](https://forums.creativeclouddeveloper.com/t/photoshop-batchplay-write-xmpmetadata-works-for-document-but-not-layer/12393/2 "2026-10-30T23:32:52Z")

</div>

> [@markbargen](#):
>
> `let result = await setDocumentXMP`

Seems you don’t call it?

---

<div class="post-metadata">

**Author:** ![markbargen](https://avatars.discourse-cdn.com/v4/letter/m/c57346/32.png) [@markbargen](https://forums.creativeclouddeveloper.com/u/markbargen)\
**Post date:** [October 31, 2026, 12:14am UTC](https://forums.creativeclouddeveloper.com/t/photoshop-batchplay-write-xmpmetadata-works-for-document-but-not-layer/12393/5 "2026-10-31T00:14:40Z")

</div>

I’m sorry … that was a cut-and-paste error while assembling the text for this post. I do in fact call the correct “setLayerXMP” function …

I’ve corrected the original post …

---

<div class="post-metadata">

**Author:** ![Kayrock](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/kayrock/32/4748_2.png) [@Kayrock](https://forums.creativeclouddeveloper.com/u/Kayrock)\
**Post date:** [October 31, 2026, 1:03am UTC](https://forums.creativeclouddeveloper.com/t/photoshop-batchplay-write-xmpmetadata-works-for-document-but-not-layer/12393/6 "2026-10-31T01:03:24Z")

</div>

It’s the read, not the write.

`new XMPMeta(xmpData)` gets the batchPlay result instead of the string inside it, so it parses nothing and gives you back an empty object. That’s your empty `<rdf:Description>`. Your re-read does the same thing, so it can’t show the appended item even when the write worked.

```js
const r = await action.batchPlay([...], { synchronousExecution: true });
const meta = new XMPMeta(r[0].XMPMetadataAsUTF8);

```

Easy way to check: log `r[0].XMPMetadataAsUTF8.length` after your read.

Also, `[{}]` is what a successful set returns. A refusal comes back as an error descriptor instead, so `[{}]` wasn’t telling you anything was wrong.

---

<div class="post-metadata">

**Author:** ![markbargen](https://avatars.discourse-cdn.com/v4/letter/m/c57346/32.png) [@markbargen](https://forums.creativeclouddeveloper.com/u/markbargen)\
**Post date:** [October 31, 2026, 10:05am UTC](https://forums.creativeclouddeveloper.com/t/photoshop-batchplay-write-xmpmetadata-works-for-document-but-not-layer/12393/7 "2026-10-31T10:05:05Z")

</div>

Well, duh! Of course! It’s obvious once it’s pointed out. Thanks.
