How To Get BatchPlay To Work With API 2

So if I have you correct, it will go something like this…

await core.executeAsModal(() => {

    //  BatchPlay stuff goes here

   //  More BatchPlay stuff goes here

   //  Even More BatchPlay stuff goes here


Yes, and you can also have any other JS coding between the batch Plays. You can consolidate the entire history to that 1 function. The new suspend history works awesome, which really has me bummed because I need that too for the plugin I am currently working on. So basically, I had to decide between history state consolidation and user dialog interaction. The user dialog interaction was the far higher priority though.

Do you have any sample code for the history or is the documentation easy to follow

Not really without piecing somthign together from my rat’s nest of coding in my plugins.

Just make sure to use async on the execute as modal function. See the plugin example from the link of where it uses async.

Really, it is very simple once you figure out where to put the executeAsModal.

I still cannot get this BatchPlay to work with PS 23.0.0

I downloaded your ccx example and even put my BatchPlay code inside your exeModal function but yet it will not run for some reason.

As a last resort, I even recorded a new recording with Alchemist but nothing.

var app = require('photoshop').app;
var batchPlay = require("photoshop").action.batchPlay;
var core = require('photoshop').core;
var exeModal = require('photoshop').core.executeAsModal;
var psAlert = require('photoshop').core.showAlert;

document.getElementById("test").addEventListener("click", async function () {

  await exeModal(async function () {

    await batchPlay(
        _obj: "fill",
        using: {
          _enum: "fillContents",
          _value: "foregroundColor"
        opacity: {
          _unit: "percentUnit",
          _value: 100
        mode: {
          _enum: "blendMode",
          _value: "normal"
        _options: {
          dialogOptions: "dontDisplay"
      }], {
        synchronousExecution: false,
        modalBehavior: "fail"



The Manifest I tried looks like this

"host": [{
    "app": "PS",
    "minVersion": "23.0.0",
    "data": {
      "apiVersion": 2
  "manifestVersion": 4,

It is because you have the modalBehavior option set to “fail”. It needs to be “execute” or default. Just use {} for the batch play options and it will set them to default.

So remove this

        synchronousExecution: false,
        modalBehavior: "fail"

and replace it with

Thank You, that has fixed it.
With your Dialog issue, do you see this as an oversight or something which has been done deliberately to only allow one plugin talking back to Photoshop at any given time

And another note with this. There are some timing issues thatcan occur on API 1 with it set to “fail” which will cause processing to just stop. I working with one of the Adobe devs to troubleshoot this. At times, Photoshop will go into a brief modal state and then the API 1 [processing will stop if that occurs and it is set to fail. The workaround in API 1 for this is to set modalBehavior to “wait” as a workaround. Since this was occurring randomly in several places, I set them all to “wait” for my API 1 plugins.

For the "dialogOptions": "display", I don’t know if it is a bug or by design. My best guess is that it is working as designed… at least for now. When running an executeAsModal, Photoshop is in a modal state so the user should not have any control of Photoshop dialogs. Using "dialogOptions": "display" will pop up the dialog but the user just can’t interact or even escape out of it. So it is doing exactly what I would expect.

If there were an option to not use executeAsModal in API 2 then you could have the option. As of now, executeAsModal is required so there is no workaround as far as I can tell.

Are you moving over to API 2 because you need access to the Single History state and extra DOM features and because API will be depreciated and want to stay ahead of the game.

For all of those reasons and more. I really want the single history state.

But beyond that, I don’t want the user to be able to click on anything in the Photoshop menu or for Photoshop to try to use keyboard shortcuts while the processing is running.

I have several batch processing plugins. If the user is pressing keys while it runs the Photoshop can pick those keystrokes up as keyboard shortcuts and mess up the batch processing. For example, in one of my plugins, the alt key pressed at the wrong time will cause a subtract from selection instead of a regular selection and really mess up what it is doing. Users will alt+tab to switch back and forth from Photoshop to whatever else they are doing periodically to check on the batch. The alt key when doing the alt+tab will can mess up the batch processing if pressed at the wrong time. I’m pretty sure that executeAsModal will fix this… although I have not converted that plugin yet to confirm it.

If you happen to find an example on how to implement this HistoryState, it would be appreciated. I have looked at the docs but they don’t really go into much detail from what I can see

The example copied/pasted right out of the Adobe docs will work without having to change anything.

//For ease of typing, I define as global
var exeModal = require('photoshop').core.executeAsModal;

//run function using execute as modal. Use await for this (you must be running from another async function to use await)
await exeModal(doStuff, {"commandName": "Doing things now"});}

async function doStuff(executionContext){
    let hostControl = executionContext.hostControl;

    // Get an ID for a target document
    let documentID = await app.activeDocument._id;

    // Suspend history state on the target document
    // This will coalesce all changes into a single history state called
    // 'Custom Command'
    let suspensionID = await hostControl.suspendHistory({
        "historyStateInfo": {
            "name": "Your History State Name",
            "target": [ {_ref: "document", _id: documentID}]
Do stuff here. It can be batchPlay or any other javascript code
await hostControl.resumeHistory(suspensionID);    

Thanks, I had not seen that example before. Just tried it and it works great.

Hm, I really hope this will not happen too quickly. Feels like I’m spending more time migrating plugins between different versions / technologies than actually building new plugins :zipper_mouth_face: (at first CEP → UXP and now API1 → API2… what will come next?)

I think it is on this page… but the page now gives a 404 error. The 404 errors have been pretty common on the “stage” documents. I need to start taking screenshots when I have the chance.

This page that references it is still up

In order to allow plugin developers to gradually move to the new model, Photoshop 2022 supports both the original and the new JavaScript modes. A plugin uses the apiVersion field to specify which model it uses.

  • apiVersion of 1 signifies that the plugin is using the original Photoshop 2021 implementation.
  • apiVersion of 2 signifies that the plugin is using the new modal JavaScript feature.

With the introduction of apiVersion = 2, the original implementation is formally deprecated, and support for apiVersion 1 will be removed in a future major update to Photoshop. As such a number of new features are only available for apiVersion 2 plugins. apiVersion 2 only features include: new DOM v2, support for suspend and resume of multiple history states at the same time.

Photoshop Product specific manifest (

1 Like

That doesn’t tell us anything about whether or not modeless Photoshop dialog interaction will be supported in API 2. That is a huge deal for some plugins if that functionality gets dropped. I really wish we had some clarification on this.

Does it all mean that if I’m using api 2 and batch play, and for example the batch play will ask user to set the radius of Gaussian blur, it will not work?

That was true when I replied back in October. Last I checked a couple weeks ago, it was fixed for the case where you were just showing 1 dialog per executeAsModal function. However, if you do 2 steps that show the dialog anywhere within the same executeAsModal function then Photoshop would still freeze on the second dialog. Also, if you use a showAlert anywhere after the show dialog in the executeAsModal function then it was freezing too.

I put in a bug report on this in the pre-release group but there hasn’t been any updates to the bug post. However, I haven’t actually tested in a couple of weeks in the latest beta release so there is a chance it has been fixed since I last checked and the bug post wasn’t updated. I’m not sure how often the bug posts actually get updated.