I now the Datamerge feature, but it is not quite what I want. I have a CSV with multiple rows and i want data from specific rows and specific columns put into my document. Obviously, data merge cant do this. But I just saw that inDesign can get skripted. I'm not new to coding, I just didnt do this with ID before.

lets say I have foo.csv


How can I:

  • read a csv
  • get a row/column (lets say 'dt22') from it
  • put it into a text-field in the document.

2 Answers 2


This question is probably off topic. It's a bit too broad. We don't know what you know about InDesign scripting, what you have tried or why you are trying to do this. And it's more about coding than about graphic design.

Anyways, I'll show you a very basic way of doing what you ask for which you might be able to use as a starting point.

First you can load the contents of your csv file and save it to a variable:

var file = new File("D:/Desktop/test.csv");
var contents = file.read();

Then you can turn the raw text of the csv into a 2D array by first splitting it by newlines and then loop through each line and split by commas:

var data = contents.split("\n");
for (var i = 0; i < data.length; i++) {
  data[i] = data[i].split(",");

You can then get the contents of a specific cell like this:


Now it gets more complicated. Selecting the text frame you want can be really tricky and cumbersome depending on how your document is structured.

A simple solution could be to name your text frames in the Layers panel:

You can then access them in the script via an object containing all text frames in the active document and its itemByName method:

var textFrames = app.activeDocument.textFrames;
var textFrameA = textFrames.itemByName("FrameA");
var textFrameB = textFrames.itemByName("FrameB");

The contents of each text frame can be filled with data like this:

textFrameA.contents = data[1][2];
textFrameB.contents = data[2][0];

If this is the beginning of a good workflow is another matter. I personally never need scripting like this. Setting it up takes longer than copy/pasting manually. But of course if you have hundreds of documents structured in the exact same way, this might be a good idea. If I knew what you are trying to achieve I would perhaps recommend a totally different workflow.

(This InDesign scripting reference is very helpful.)


I wrote this little script that converts entries like this {{23746:ABCD}} with csv's row where ID is 23746 and replaces the field with the column entry of ABCD. CSV currently needs EOL as last entry to be new-line-aware.

The line

var csvSep = ";";

sets the used csv separator.

Example csv:


{{23746:ABCD}} will be replaced with foo


function main() {
    var entries = readCSVFile();
    function lookupEntry($match, $id, $field) {
        var entry = entries[$id];
        if (!entry)
            return "[[!NO REF!]]";
        return entry[$field];

    app.findGrepPreferences = NothingEnum.nothing;
    app.changeGrepPreferences = NothingEnum.nothing;
    app.findChangeGrepOptions.includeFootnotes = true;
    app.findChangeGrepOptions.includeHiddenLayers = true;
    app.findChangeGrepOptions.includeLockedLayersForFind = false;
    app.findChangeGrepOptions.includeLockedStoriesForFind = false;
    app.findChangeGrepOptions.includeMasterPages = false;
    app.findGrepPreferences.findWhat = "\{\{[^:]*\:[^}]*\}\}";
    var hits = app.activeDocument.findGrep();
    for (var i = 0; i < hits.length; i++) {
        hits[i].contents = hits[i].contents.replace(/\{\{([^:]*)\:([^}]*)\}\}/g,lookupEntry);

    app.findGrepPreferences = NothingEnum.nothing;
    app.changeGrepPreferences = NothingEnum.nothing;

function readCSVFile() {
    var csvFilter = function(f){return/\.csv$/i.test ( f.name ); };
    if( $.os.match("Windows") ){ csvFilter = "*.csv" };
    f = File.openDialog ("Please select the CSV File…", csvFilter, false);
    if ( !f ) return;
    var csvSep = ";";
    var csvEOL = 'EOL';

    var csvHeaders = readCSVLine(f, csvSep, csvEOL);
    var entries = [];
    while (!f.eof) {
        var row = readCSVLine(f, csvSep, csvEOL);
        var entry = [];
        for(var column = 0 ; column < csvHeaders.length; column++) {
            var col = row[column];
            if (col.charAt(0) === '"' && col.charAt(col.length -1) === '"') {
                col = col.substr(1,col.length - 2);
            entry[csvHeaders[column]] = col;
        entries[entry['ID']] = entry;
    return entries;

function readCSVLine(file, separator, endoflinemark)
    var ret = [];
    while (ret[ret.length-1] != endoflinemark && !file.eof) {
        pass = file.readln().split(separator);
        if (ret.length > 0 && pass.length > 0)
            ret[ret.length-1] = ret[ret.length-1] + pass.shift();
        ret = ret.concat(pass);
    return ret;
app.doScript(main,ScriptLanguage.JAVASCRIPT,[],UndoModes.ENTIRE_SCRIPT,'SHTC: Populate by .rhavin;)');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.