1. ACF InDesign action return contract

An ACF function invoked from an InDesign package menu or floating palette controls the next host action through its return value. Simple strings become messages. Native ACF JSON objects can request messages, package reloads, document operations, or no further action.

This page documents version 1 of the published return contract, including the currently implemented document operations and their JSON fields.

  1. ACF InDesign action return contract
    1. Return types at a glance
    2. Action function signatures
    3. The action information object
    4. General JSON response rules
    5. indesign.noop
    6. indesign.message
    7. indesign.reload_packages
    8. indesign.document
      1. Advertisement example
      2. Newspaper-edition example
      3. Root fields
      4. Creation fields
    9. indesign.operations
      1. Root fields
      2. Transaction object
      3. Completion object
    10. Command execution and identity
      1. Common creation fields
      2. Target selectors
    11. Geometry and placement
      1. Explicit bounds
      2. Coordinate placement
      3. Interactive placement
      4. Relative placement
    12. Implemented operation names
    13. define_paragraph_styles
      1. Paragraph-style properties
    14. define_character_styles
      1. Character-style properties
    15. set_markdown_styles
      1. Paragraph roles
      2. Character roles
    16. create_text_frame
      1. Plain text
      2. Markdown text
      3. Fixed and automatic height
      4. Columns and gutter
      5. Automatic page continuation
    17. set_text
    18. place_image
      1. Fixed frame
      2. Image-sized frame
      3. Image in a layout canvas
    19. set_image
    20. group_items
    21. Complete placement example
    22. Validation and error handling
    23. Compatibility rules
    24. Related documentation

From an ACF package to a native InDesign action

1.1. Return types at a glance

ACF function result InDesign behavior
Empty return or empty STRING Finish without further host action.
Non-empty STRING Show an InDesign information dialog containing the string.
JSON with type: "indesign.noop" Finish without further host action while preserving a JSON return type.
JSON with type: "indesign.message" Show a native information, warning, or error dialog.
JSON with type: "indesign.reload_packages" Ask the user whether packages should be rescanned and menus rebuilt.
JSON with type: "indesign.document" Open an existing InDesign document or create and save it when missing.
JSON with type: "indesign.operations" Validate and execute ordered document operations.
Unsupported ACF type Show and log an unsupported return-type error.
Runtime exception Catch it at the Adobe SDK boundary, show an error dialog, and append it to the plugin log.

Package actions should return native JSON, not JSON serialized into a string. String-encoded JSON exists only for transitional compatibility.

An ACF function must also keep one consistent return type. If a JSON-returning function has a cancelled or empty branch, return indesign.noop from that branch instead of returning an empty string.

1.2. Action function signatures

A function referenced by a package menu or dispatched palette action can use either signature:

function Package_action ()
function Package_action (JSON info)

The zero-parameter form remains valid. The one-parameter form must have exactly one JSON parameter. InDesign supplies a fresh versioned context snapshot when the user invokes the action.

The package discovery function <package_name>_menu() is separate and always has zero parameters.

1.3. The action information object

The one-parameter action receives an object like this:

{
  "type": "indesign.action_info",
  "version": 1,
  "units": "pt",
  "document": {
    "name": "Tomorrow's Newspaper.indd",
    "path": "/Volumes/News/Tomorrow's Newspaper.indd",
    "saved": true,
    "modified": false,
    "readOnly": false
  },
  "page": {
    "index": 4,
    "name": "4",
    "width": 595.276,
    "height": 841.89,
    "margins": {
      "left": 36,
      "top": 36,
      "right": 36,
      "bottom": 42
    },
    "placementArea": {
      "origin": "top_left_margin",
      "width": 523.276,
      "height": 763.89
    }
  }
}
Field Type Meaning
type string Always indesign.action_info.
version integer Action-information schema version. Version 1 is 1.
units string Always pt in version 1.
document object or null Active document information, or null when no document is active.
page object or null Active layout page information, or null when no page is active.
palette object, optional Current palette values when invoked through returnAction: "dispatch".

document.path is an absolute path only after the document has been saved. It is null for a new unsaved document or when InDesign cannot provide a filesystem path.

page.index is the one-based document page index. page.name is the displayed InDesign page name and can differ from the index.

The placement area is the usable page rectangle inside the margins:

placement width  = page width  - left margin - right margin
placement height = page height - top margin  - bottom margin

Version 1 document-operation coordinates use the top-left margin as origin. This means [0, 0] is the upper-left corner inside the page margins.

1.4. General JSON response rules

Every JSON action response must be an object containing:

Field Required Type Meaning
type Yes string Host action type.
version Yes integer Must be 1 for this contract.
extensions No object Package-defined data not interpreted by version 1.

Unknown response types and unsupported versions are errors. Unknown fields are also rejected unless the specification explicitly allows them. Put package-private additions under extensions to avoid hiding misspelled contract fields.

1.5. indesign.noop

Use indesign.noop when a JSON-returning action has completed but does not need another host action. It is particularly useful after a cancelled dialog or after open_palette() has opened a modeless palette.

return JSON(
    "type", "indesign.noop",
    "version", 1
);

JSON form:

{
  "type": "indesign.noop",
  "version": 1
}
Field Required Type Meaning
type Yes string Must be indesign.noop.
version Yes integer Must be 1.
extensions No object Package-defined metadata.

No other fields are accepted.

1.6. indesign.message

Use indesign.message to request a native InDesign message dialog.

return JSON(
    "type", "indesign.message",
    "version", 1,
    "severity", "information",
    "title", _("Article status"),
    "message", _("No articles are scheduled for this page.")
);

JSON form:

{
  "type": "indesign.message",
  "version": 1,
  "severity": "information",
  "title": "Article status",
  "message": "No articles are scheduled for this page."
}
Field Required Type Meaning
type Yes string Must be indesign.message.
version Yes integer Must be 1.
message Yes string Dialog text.
severity No string information, warning, or error. Defaults to information.
title No string Optional title when supported by the native alert.
extensions No object Package-defined metadata.

An ordinary non-empty ACF STRING also produces an information dialog. Use indesign.message when severity or a consistent JSON return type matters.

1.7. indesign.reload_packages

Use indesign.reload_packages when an action has changed package-related state and should offer to rescan compiled packages. Language installation is a typical example because package menu functions must run again before translated menu labels appear.

return JSON(
    "type", "indesign.reload_packages",
    "version", 1,
    "message", _("The language was installed. Reload ACF packages now?")
);

JSON form:

{
  "type": "indesign.reload_packages",
  "version": 1,
  "message": "The language was installed. Reload ACF packages now?"
}
Field Required Type Meaning
type Yes string Must be indesign.reload_packages.
version Yes integer Must be 1.
message Yes string Confirmation shown before reloading.
extensions No object Package-defined metadata.

When the user accepts, the plugin rescans compiled packages, executes package startup functions, and rebuilds dynamic menus. Choosing Later leaves the current installed packages and menus active.

1.8. indesign.document

indesign.document establishes a document from an absolute .indd path. By default, an existing document is opened and a missing document is created, saved at that path, and shown in a layout window. Creation settings never modify a document that already exists.

1.8.1. Advertisement example

return JSON(
    "type", "indesign.document",
    "version", 1,
    "path", "/Users/editor/Advertisements/AD-18425.indd",
    "units", "cm",
    "document", JSON(
        "pageSize", JSON("width", 15, "height", 10),
        "pages", 1,
        "facingPages", false,
        "margins", JSON(
            "top", 0, "bottom", 0,
            "inside", 0, "outside", 0
        ),
        "bleed", JSON(
            "top", 0.3, "bottom", 0.3,
            "inside", 0.3, "outside", 0.3
        )
    )
);

1.8.2. Newspaper-edition example

{
  "type": "indesign.document",
  "version": 1,
  "path": "/Volumes/Production/2026-07-25/Edition.indd",
  "ifExists": "open",
  "ifMissing": "create",
  "showWindow": true,
  "units": "mm",
  "document": {
    "pageSize": {
      "width": 280,
      "height": 400
    },
    "orientation": "portrait",
    "pages": 32,
    "facingPages": true,
    "binding": "left_to_right",
    "margins": {
      "top": 12,
      "bottom": 15,
      "inside": 12,
      "outside": 10
    },
    "columns": {
      "count": 6,
      "gutter": 4
    },
    "bleed": {
      "top": 3,
      "bottom": 3,
      "inside": 3,
      "outside": 3
    }
  },
  "completion": {
    "message": "The newspaper edition is ready."
  }
}

1.8.3. Root fields

Field Required Type Meaning
type Yes string Must be indesign.document.
version Yes integer Must be 1.
path Yes string Absolute path ending in .indd.
ifExists No string open or error; defaults to open.
ifMissing No string create or error; defaults to create.
showWindow No boolean Open a layout window for a newly opened or created document; defaults to true.
units No string pt, mm, cm, or in; defaults to pt.
document Conditional object Required when a missing document may be created. Ignored when the file already exists.
completion No object Optional { "message": "..." } success notification.
extensions No object Package-defined extension data.

1.8.4. Creation fields

Field Required Type Meaning
pageSize Yes object Positive width and height in the root units.
orientation No string as_specified, portrait, or landscape; defaults to as_specified. Portrait/landscape swaps the supplied dimensions when necessary.
pages No integer Initial page count from 1 through 10000; defaults to 1.
facingPages No boolean Use two-page spreads; defaults to false.
binding No string left_to_right or right_to_left; defaults to left_to_right.
margins No object Non-negative top, bottom, inside, and outside; omitted values are zero.
columns No object count from 1 through 100 and non-negative gutter. Gutter must be zero or omitted for one column.
bleed No object Non-negative top, bottom, inside, and outside; omitted values are zero.

The destination directory must already exist. If the file is already open, the plugin reuses that document rather than opening a duplicate. Use a later menu or palette action returning indesign.operations to place content in the newly active layout.

1.9. indesign.operations

indesign.operations requests one or more native document changes. The complete response is validated before execution begins.

{
  "type": "indesign.operations",
  "version": 1,
  "units": "pt",
  "coordinateSpace": "page",
  "transaction": {
    "name": "Place scheduled article",
    "cancelPolicy": "keep"
  },
  "commands": [],
  "completion": {
    "message": "The article was placed successfully."
  }
}

1.8.3. Root fields

Field Required Type Meaning
type Yes string Must be indesign.operations.
version Yes integer Must be 1.
commands Yes array Ordered operation objects.
units No string Default units: pt, mm, cm, or in. Defaults to pt.
coordinateSpace No string Must be page in version 1. Defaults to page.
transaction No object Operation name and cancellation policy.
metadata No object Response-level package metadata.
completion No object Optional success notification.
extensions No object Package-defined extension data.

Each command can override the root units value.

1.9.2. Transaction object

{
  "name": "Place article: New harbour project",
  "cancelPolicy": "keep"
}
Field Required Type Meaning
name No string Human-readable transaction label. Version 1 accepts it as descriptive metadata.
cancelPolicy No string keep or rollback. Defaults to keep.

keep preserves commands completed before the user presses Escape during interactive placement.

rollback is reserved for fully reversible execution. The current implementation rejects rollback when the command list contains interactive user placement; use keep for interactive workflows.

1.9.3. Completion object

{
  "message": "The article was placed successfully."
}

The optional message string is shown after successful completion. Omit completion when no confirmation dialog is wanted.

1.10. Command execution and identity

Commands execute in array order. Commands that create page objects can define temporary and persistent identifiers.

1.10.1. Common creation fields

Field Required Type Meaning
op Yes string Operation name.
id No string Batch-local identifier, unique in this response.
persistentId No string Package-owned identity stored on the InDesign object.
page No string Currently only active is implemented.
units No string Command-level unit override.
metadata No object Metadata stored with the created object when supported.
extensions No object Package-defined extension data.

id exists only while one indesign.operations response is executing. Later commands can refer to an earlier id.

persistentId survives separate action invocations and document save/reopen. The plugin stores it together with the calling package name and namespace, preventing another package from finding the object merely by guessing the same ID.

Batch-local IDs must be unique within the response. Persistent IDs attached to create commands must also be unique within that response.

Use stable logical identifiers:

article:18425:headline
article:18425:body
article:18425:main_image
product:SKU-4821:price

Moving an object or changing its text must not change its persistent ID.

1.10.2. Target selectors

A batch-local target is a string:

{
  "op": "set_text",
  "target": "headline",
  "text": "Updated during the current operation"
}

A persistent target is an object:

{
  "op": "set_text",
  "target": {
    "persistentId": "article:18425:headline"
  },
  "text": "Updated in a later action"
}

Persistent lookup must find exactly one compatible page item in the active document. No match and duplicate matches are both errors.

1.11. Geometry and placement

Commands that create a page item use either bounds, or size together with place. These forms cannot be mixed.

1.11.1. Explicit bounds

{
  "bounds": {
    "left": 0,
    "top": 0,
    "right": 320,
    "bottom": 210
  }
}

All values use the command or root units. right must exceed left, and bottom must exceed top.

create_text_frame can omit bottom to request automatic height. place_image always requires all four bounds.

1.11.2. Coordinate placement

{
  "size": [320, 210],
  "place": [0, 0]
}

size is [width, height]. place is [left, top], relative to the top-left margin of the active page.

1.11.3. Interactive placement

{
  "size": [320, 210],
  "place": "user"
}

The plugin pauses the command sequence, activates the ACF placement tool, and waits for a valid page click. The click becomes the top-left anchor. After placement, the next command runs. Several commands can request user placement and are handled in command-array order.

Escape cancels the uncompleted commands according to transaction.cancelPolicy.

The expanded object form for user placement is reserved but is not implemented in version 1. Use the exact string "user".

1.11.4. Relative placement

{
  "size": [320, 80],
  "place": {
    "mode": "relative",
    "relativeTo": "headline",
    "edge": "bottom",
    "offset": [0, 8],
    "referenceBounds": "frame",
    "matchWidth": false
  }
}
Field Required Type Meaning
mode Yes string Must be relative.
relativeTo Yes string Batch-local id of an earlier create command.
edge Yes string top, right, bottom, or left.
offset No array [x, y]; defaults to [0, 0].
referenceBounds No string frame (default), or content for the actual content inside a referenced graphic frame.
matchWidth No boolean For create_text_frame, replace the requested width with the selected reference bounds' width.

Relative placement uses the referenced object's final bounds after text composition, column setup, and automatic height. The new item inherits the referenced item's page.

Using referenceBounds: "content" together with matchWidth: true makes an image caption align with the photograph inside a wider image canvas.

The offset is applied after edge alignment.

1.12. Implemented operation names

The current native executor implements:

Other operation names reserved by design documents are not yet implemented. They produce a clear unsupported op error rather than being silently ignored.

1.13. define_paragraph_styles

Creates missing paragraph styles or updates the supplied properties of existing styles.

{
  "op": "define_paragraph_styles",
  "mode": "add_missing",
  "styles": [
    {
      "name": "News Headline",
      "properties": {
        "fontFamily": "Times New Roman",
        "fontStyle": "Bold",
        "pointSize": 28,
        "leading": 30,
        "spaceAfter": 6,
        "alignment": "center"
      }
    }
  ]
}
Field Required Type Meaning
op Yes string Must be define_paragraph_styles.
mode No string add_missing or force_update; defaults to add_missing.
styles Yes array One or more style definitions.
extensions No object Package-defined extension data.

Each entry in styles has a required non-empty name and a required properties object.

1.13.1. Paragraph-style properties

Property Type Meaning
fontFamily string Installed font family. Supply together with fontStyle.
fontStyle string Installed style within fontFamily. Supply together with fontFamily.
pointSize number Font size, greater than zero.
leading number Line leading, greater than zero.
spaceBefore number Paragraph space before.
spaceAfter number Paragraph space after.
leftIndent number Left paragraph indent.
rightIndent number Right paragraph indent.
firstLineIndent number First-line indent; a negative value creates a hanging indent.
alignment string Paragraph alignment value listed below.
shading object Paragraph background color and offsets.
border object Paragraph border color, weight, and offsets.

Supported alignment values are:

Shading example:

{
  "shading": {
    "color": "Paper",
    "tint": 100,
    "offset": [3, 4, 3, 4]
  }
}

Border example:

{
  "border": {
    "color": "Black",
    "tint": 25,
    "weight": 0.25,
    "offset": [0, 0, 0, 0]
  }
}

color can be Black, Paper, or the exact name of a document swatch. tint is from 0 through 100. weight must be greater than zero. An offset is [left, top, right, bottom]. Paragraph-style typographic measurements, border weights, and decoration offsets are always points; they do not inherit the operation envelope's units.

With add_missing, an existing style is left untouched. This lets a designer customize document styles while later package revisions add only newly introduced styles. With force_update, the supplied properties are reapplied to existing styles, and text already using those styles updates immediately.

Properties omitted during force_update are not reset; only supplied properties are changed.

spaceBefore, spaceAfter, leftIndent, and rightIndent cannot be negative. firstLineIndent may be negative to create a hanging indent. Style names must be unique within the command.

1.14. define_character_styles

Creates missing character styles or updates the supplied properties of existing styles.

{
  "op": "define_character_styles",
  "mode": "add_missing",
  "styles": [
    {
      "name": "News Strong Emphasis",
      "properties": {
        "fontStyle": "Bold Italic"
      }
    },
    {
      "name": "News Inline Code",
      "properties": {
        "fontFamily": "Menlo",
        "fontStyle": "Regular",
        "pointSize": 9
      }
    }
  ]
}
Field Required Type Meaning
op Yes string Must be define_character_styles.
mode No string add_missing or force_update; defaults to add_missing.
styles Yes array One or more character-style definitions.
extensions No object Package-defined extension data.

1.14.1. Character-style properties

Property Type Meaning
fontFamily string Optional font-family override. If supplied, fontStyle is also required.
fontStyle string Face such as Bold or Italic. It can be supplied alone to inherit the paragraph style's family.
pointSize number Optional font-size override, greater than zero.
strikethrough boolean Enables or disables strikethrough.

The modes behave like define_paragraph_styles. Inheriting the paragraph font while applying only fontStyle is normally the best choice for Markdown strong and emphasis decorations.

Each properties object must contain at least one supported property, and style names must be unique within the command.

1.15. set_markdown_styles

Sets the document style-name mapping used by subsequent Markdown text operations. The mapping remains active for later Markdown blocks until another set_markdown_styles command replaces it.

{
  "op": "set_markdown_styles",
  "paragraphStyles": {
    "paragraph": "News Body",
    "paragraphIndented": "News Body Indented",
    "heading1": "News Heading 1",
    "heading2": "News Heading 2",
    "bullet": "News Bullet",
    "codeBlock": "News Code Block",
    "codeBlockIndented": "News Code Block Indented",
    "tableLeft": "News Table Left",
    "tableCenter": "News Table Center",
    "tableRight": "News Table Right"
  },
  "characterStyles": {
    "strong": "News Strong",
    "emphasis": "News Emphasis",
    "strongEmphasis": "News Strong Emphasis",
    "strike": "News Strike",
    "inlineCode": "News Inline Code",
    "tableHeader": "News Table Header"
  }
}
Field Required Type Meaning
op Yes string Must be set_markdown_styles.
paragraphStyles Yes object Paragraph-role to style-name mapping.
characterStyles Yes object Character-role to style-name mapping; may be empty.
extensions No object Package-defined extension data.

1.15.1. Paragraph roles

Key Required Meaning
paragraph Yes Ordinary paragraph style and fallback for unspecified paragraph roles.
paragraphIndented No Paragraph nested inside a Markdown list.
heading1heading6 No ATX heading levels # through ######.
bullet No Unordered list item.
codeBlock No Top-level fenced code block.
codeBlockIndented No Fenced code block nested inside a list.
tableLeft No Left-aligned table cell.
tableCenter No Center-aligned table cell.
tableRight No Right-aligned table cell.

1.15.2. Character roles

Key Meaning
strong **bold** text.
emphasis *italic* text.
strongEmphasis Combined bold and italic text.
strike ~~strikethrough~~ text.
inlineCode Inline backtick code.
tableHeader Header-row text in a Markdown table.

Referenced styles must already exist in the active document. Define them earlier in the same command list when necessary.

The current native Markdown subset supports paragraphs, ATX headings, unordered lists, strong/emphasis/strong-emphasis/strikethrough, inline code, fenced code blocks, links, standalone images, and pipe tables. Ordered lists and embedded HTML are not part of version 1.

1.16. create_text_frame

Creates a text frame, inserts plain text or Markdown, optionally applies a paragraph style, and can calculate its height from the composed text.

{
  "op": "create_text_frame",
  "id": "headline",
  "persistentId": "article:18425:headline",
  "page": "active",
  "size": {
    "width": 523.276
  },
  "place": [0, 220],
  "text": "A headline that can wrap",
  "style": {
    "paragraphStyle": "News Headline"
  }
}
Field Required Type Meaning
op Yes string Must be create_text_frame.
id No string Batch-local identifier.
persistentId No string Persistent document identity.
page No string Currently only active; defaults to the active page.
units No string pt, mm, cm, or in.
bounds Conditional object Explicit rectangle; omit bottom for automatic height.
size Conditional array or object Frame size. Use together with place.
place Conditional array, string, or object Coordinate, user, or relative placement.
text No string or object Plain Unicode text or Markdown definition.
style No object Plain-text paragraph style. Not valid together with Markdown text.
columns No integer Positive column count; defaults to 1.
gutter Conditional number Non-negative inter-column distance. Required only when columns is greater than 1.
overflow No object Automatic-page continuation settings.
metadata No object Metadata stored with the frame when supported.
extensions No object Package-defined extension data.

Supply either bounds, or both size and place. Do not combine these geometry forms.

1.16.1. Plain text

{
  "text": "Unicode text: blåbær, français, 日本語",
  "style": {
    "paragraphStyle": "News Body"
  }
}

All text-placement operations use Unicode. A style object accepts only paragraphStyle.

1.16.2. Markdown text

{
  "text": {
    "format": "markdown",
    "content": "## Native Markdown\n\nText with **strong emphasis**.",
    "sourcePath": "/Volumes/Editorial/articles/article-18425.md"
  }
}

format must be markdown; content is required. Optional sourcePath establishes the base directory for relative Markdown image paths. Do not combine Markdown text with the plain-text style field; Markdown uses the active mapping from set_markdown_styles.

1.16.3. Fixed and automatic height

An array size is always fixed:

{
  "size": [320, 90],
  "place": [0, 0]
}

An object size can omit height:

{
  "size": {
    "width": 320
  },
  "place": [0, 0]
}

With no height, InDesign composes the text and adjusts the frame bottom. Explicit bounds request the same behavior when bottom is omitted:

{
  "bounds": {
    "left": 0,
    "top": 0,
    "right": 320
  }
}

Automatic height is useful for headlines, ingress blocks, interactive placement, and relative layouts because the next relative item uses the resulting final bounds. It is not valid with auto_add_pages.

1.16.4. Columns and gutter

{
  "columns": 3,
  "gutter": 12
}

For a multi-column text frame, the supplied width means the complete article width. The plugin calculates the individual column width as:

column width = (total width - gutter × (columns - 1)) / columns

Do not supply gutter when columns is 1. When columns is greater than 1, gutter is required.

1.16.5. Automatic page continuation

{
  "op": "create_text_frame",
  "id": "article_body",
  "persistentId": "article:18425:body",
  "page": "active",
  "bounds": {
    "left": 0,
    "top": 0,
    "right": 523.276,
    "bottom": 763.89
  },
  "text": {
    "format": "markdown",
    "content": "A long Markdown article..."
  },
  "overflow": {
    "mode": "auto_add_pages",
    "maxAddedPages": 50
  }
}
Overflow field Required Type Meaning
mode Yes string Must be auto_add_pages.
maxAddedPages No integer Safety limit from 1 through 9998; defaults to 100.

The first frame must have a fixed height on the active page. It can use explicit bounds or a fixed size with coordinate placement. If text is overset, the executor adds pages, creates frames inside each new page's margins, and threads them together until the story fits or the safety limit is reached.

Continuation frames derived from persistentId: "article:18425:body" receive identities such as:

article:18425:body:continuation:1
article:18425:body:continuation:2

Automatic page continuation cannot be combined with relative placement, interactive placement, or automatic height. Coordinate placement with a fixed width and height is supported.

1.17. set_text

Replaces the contents of an existing text frame.

{
  "op": "set_text",
  "target": {
    "persistentId": "article:18425:headline"
  },
  "text": "Updated headline",
  "fitHeight": true
}
Field Required Type Meaning
op Yes string Must be set_text.
target Yes string or object Earlier batch-local id, or { "persistentId": "..." }.
text Yes string or object Plain Unicode text or Markdown definition.
fitHeight No boolean Recompose and adjust the frame height after replacement. Defaults to false.
extensions No object Package-defined extension data.

Markdown replacement uses:

{
  "format": "markdown",
  "content": "Updated **Markdown** content"
}

Unlike create_text_frame, the current set_text Markdown object accepts only format and content; it does not accept sourcePath.

fitHeight: true changes the height but does not move the frame. This supports refreshing placed editorial content while respecting a designer's manual position changes.

1.18. place_image

Creates an image frame and places a local image file. The source path must exist when the command is validated.

SVG compatibility: InDesign supports SVG placement, but its SVG renderer has a more limited feature set than modern browsers and dedicated SVG editors. Complex SVG files may appear incomplete whether they are placed manually or through the ACF plugin. This is an InDesign limitation, not a plugin limitation. Convert problematic SVG artwork to PDF for vector output, or to PNG or TIFF for raster placement.

1.18.1. Fixed frame

{
  "op": "place_image",
  "id": "main_image",
  "persistentId": "article:18425:main_image",
  "page": "active",
  "size": [320, 210],
  "place": [0, 0],
  "source": "/Volumes/Images/18425-main.jpg",
  "fit": "fill_proportionally"
}
Field Required Type Meaning
op Yes string Must be place_image.
id No string Batch-local identifier.
persistentId No string Persistent document identity.
page No string Currently only active.
units No string pt, mm, cm, or in.
bounds Conditional object Fixed frame rectangle; all four sides are required.
size Conditional array or object Fixed frame or content sizing. Use with place.
place Conditional array, string, or object Coordinate, user, or relative placement.
source Yes string Existing local file path.
fit No string Fitting policy described below; defaults to none.
canvas No object Wider layout canvas for an object-sized image.
metadata No object Metadata stored with the frame when supported.
extensions No object Package-defined extension data.

Supported fit values are:

Value Behavior
none Keep intrinsic placed size; used by content sizing.
fit_proportionally Fit the entire image inside the frame without distortion.
fill_proportionally Fill the frame proportionally; excess image area can be cropped.
center Center the placed content without proportional fitting.

Explicit bounds always require left, top, right, and bottom.

1.18.2. Image-sized frame

An object size provides content-oriented sizing:

{
  "size": {
    "height": 210
  },
  "place": [0, 0],
  "source": "/Volumes/Images/18425-main.jpg"
}

height is required. If width is omitted, the plugin derives it from the image's aspect ratio. If both are supplied, they define the displayed image size. fit must be omitted or none for object sizing.

1.18.3. Image in a layout canvas

The optional canvas reserves a wider placement area while keeping the image itself smaller:

{
  "op": "place_image",
  "id": "main_image",
  "size": {
    "height": 210
  },
  "canvas": {
    "width": 523.276,
    "alignment": "center"
  },
  "place": [0, 0],
  "source": "/Volumes/Images/18425-main.jpg"
}
Canvas field Required Type Meaning
width Yes number Total layout width, at least as wide as the displayed image.
alignment No string left, center, or right; defaults to center.

canvas is valid only with object size. The canvas controls horizontal placement but is not an additional visible InDesign frame. Relative placement uses the canvas footprint by default. A relative text frame can use referenceBounds: "content" and matchWidth: true when it must align with the photograph rather than the canvas.

1.19. set_image

Replaces the linked image in an existing persistent image frame while preserving the frame geometry.

{
  "op": "set_image",
  "target": {
    "persistentId": "article:18425:main_image"
  },
  "source": "/Volumes/Images/18425-main-revised.jpg"
}
Field Required Type Meaning
op Yes string Must be set_image.
target Yes object Must be { "persistentId": "..." }. Batch-local strings are not accepted by the current implementation.
source Yes string Existing local image path.
extensions No object Package-defined extension data.

The command updates the placed content, not the frame position. This is useful when refreshing an article from an editorial system after the designer has adjusted the layout.

1.20. group_items

Creates a native InDesign group from page items created earlier in the same operation list.

{
  "op": "group_items",
  "id": "article_image_1_group",
  "persistentId": "article:18425:image_group:1",
  "items": [
    "article_image_1",
    "article_image_1_caption"
  ]
}
Field Required Type Meaning
op Yes string Must be group_items.
items Yes array At least two unique batch-local ids created by earlier create, image, or group commands.
id No string Batch-local id assigned to the new group. Later relative placements can use it as relativeTo.
persistentId No string Stable document identity for the group.
metadata No object Package-defined metadata stored on the group.
extensions No object Package-defined extension data.

The child objects keep their own persistent ids. This allows an image and its caption to move together while later set_image and set_text commands still update the individual children.

1.21. Complete placement example

This response defines document styles, establishes the Markdown mapping, places a centered image, and positions automatically sized text blocks relative to the object before them.

{
  "type": "indesign.operations",
  "version": 1,
  "units": "pt",
  "coordinateSpace": "page",
  "transaction": {
    "name": "Place article 18425",
    "cancelPolicy": "keep"
  },
  "metadata": {
    "articleId": "18425",
    "source": "Editorial API"
  },
  "commands": [
    {
      "op": "define_paragraph_styles",
      "mode": "add_missing",
      "styles": [
        {
          "name": "News Headline",
          "properties": {
            "fontFamily": "Times New Roman",
            "fontStyle": "Bold",
            "pointSize": 28,
            "leading": 30,
            "spaceAfter": 4,
            "alignment": "center"
          }
        },
        {
          "name": "News Body",
          "properties": {
            "fontFamily": "Times New Roman",
            "fontStyle": "Regular",
            "pointSize": 10,
            "leading": 12
          }
        }
      ]
    },
    {
      "op": "define_character_styles",
      "mode": "add_missing",
      "styles": [
        {
          "name": "News Strong",
          "properties": {
            "fontStyle": "Bold"
          }
        },
        {
          "name": "News Emphasis",
          "properties": {
            "fontStyle": "Italic"
          }
        }
      ]
    },
    {
      "op": "set_markdown_styles",
      "paragraphStyles": {
        "paragraph": "News Body",
        "heading1": "News Headline"
      },
      "characterStyles": {
        "strong": "News Strong",
        "emphasis": "News Emphasis"
      }
    },
    {
      "op": "place_image",
      "id": "main_image",
      "persistentId": "article:18425:main_image",
      "page": "active",
      "size": {
        "height": 220
      },
      "canvas": {
        "width": 523.276,
        "alignment": "center"
      },
      "place": [0, 0],
      "source": "/Volumes/Images/18425-main.jpg"
    },
    {
      "op": "create_text_frame",
      "id": "headline",
      "persistentId": "article:18425:headline",
      "size": {
        "width": 523.276
      },
      "place": {
        "mode": "relative",
        "relativeTo": "main_image",
        "edge": "bottom",
        "offset": [0, 8]
      },
      "text": "Harbour expansion approved",
      "style": {
        "paragraphStyle": "News Headline"
      }
    },
    {
      "op": "create_text_frame",
      "id": "body",
      "persistentId": "article:18425:body",
      "size": {
        "width": 523.276
      },
      "place": {
        "mode": "relative",
        "relativeTo": "headline",
        "edge": "bottom",
        "offset": [0, 6]
      },
      "columns": 2,
      "gutter": 12,
      "text": {
        "format": "markdown",
        "content": "The council approved the **revised plan** today."
      }
    }
  ],
  "completion": {
    "message": "Article 18425 was placed."
  }
}

1.22. Validation and error handling

The executor validates the complete response before it starts changing the document. Validation covers:

If validation fails, no command is executed. The error identifies the command index and field path, for example:

news_package.place_article: commands[3] (create_text_frame).gutter:
gutter cannot be specified when columns is 1

An error during execution is caught at the Adobe SDK boundary, written to the ACF InDesign log, and shown in a native dialog. Package code should still validate source data before returning operations—for example, resolve missing image paths before creating place_image commands.

1.23. Compatibility rules

1.24. Related documentation