<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The ETCH Blog]]></title><description><![CDATA[Tutorials and notes on generating Word, Excel and PowerPoint documents from your data with ETCH, from Oracle APEX, Python, JavaScript and Java.]]></description><link>https://get-etch.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ab92e30bc72733fdb544867/19953f01-4b8e-488e-a3fe-23867f058543.png</url><title>The ETCH Blog</title><link>https://get-etch.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 04 Nov 2026 02:52:35 GMT</lastBuildDate><atom:link href="https://get-etch.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[There's a huge problem with document templating systems and 10 ways ETCH makes it easier]]></title><description><![CDATA[A finished document template can be hard to change months later. Ten things ETCH does to keep a Word, Excel or PowerPoint template readable.]]></description><link>https://get-etch.hashnode.dev/there-s-a-huge-problem-with-document-templating-systems-and-10-ways-etch-makes-it-easier</link><guid isPermaLink="true">https://get-etch.hashnode.dev/there-s-a-huge-problem-with-document-templating-systems-and-10-ways-etch-makes-it-easier</guid><category><![CDATA[etch]]></category><category><![CDATA[Document Generation]]></category><category><![CDATA[.docx]]></category><category><![CDATA[pptx]]></category><category><![CDATA[jasperreports]]></category><category><![CDATA[xlsx]]></category><dc:creator><![CDATA[John Scott]]></dc:creator><pubDate>Fri, 30 Oct 2026 10:58:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/fe72b6e9-c137-497c-8855-074533032766.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here's something I've noticed after years of building document templates, in <a href="https://get-etch.app">ETCH</a> and long before it with systems like <a href="https://github.com/Jaspersoft/jasperreports">JasperReports</a> etc. The first version of a template is fine. You build it, you test it, the document comes out exactly how you want it and everyone is happy.</p>
<p>Then six months later someone asks for a small change. Add a line to the totals, move the delivery address, change the wording of the overdue notice. You open the template and it looks like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/314a7b03-231a-497b-8ecb-0bf76b9421d4.png" alt="The &quot;before&quot; invoice template open in Word for Mac: a page of long tags such as {{(sum lines &quot;amount&quot;) * (1 + vat_rate) | currency &quot;£&quot;}}, some in bold red, with the bill-to and deliver-to addresses written out as {{customer.billing.line1}} and so on." style="display:block;margin:0 auto" />

<p>That's an invoice. It works, and it renders the invoice further down this post. But look at what it asks of the person editing it:</p>
<ul>
<li>The total is worked out in full three times: in the overdue notice, in the totals table and in the payment line. If you want to change how it's calculated you have to find and change all three, the same way.</li>
<li>The tags are styled to look like their output, so the overdue line is one long run of red bold tags. Click in the wrong place and you risk splitting the formatting, or the tag.</li>
<li>The billing and delivery addresses are the same three lines with different paths.</li>
<li>The page doesn't look like an invoice. A tag is rarely as wide as the value it becomes, so the line breaks and column widths you see aren't the ones you'll get in the finished document.</li>
</ul>
<p>None of this is unusual. Any system that puts logic into a Word, Excel or PowerPoint file has the same problem, and my own early ETCH templates looked just like this. The good news is that most of it can be avoided, and over the last year a lot of what I've added to ETCH has been about exactly that. Here's the same invoice rebuilt:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/abfa1680-078d-4dc6-9739-31c63328cec0.png" alt="The &quot;after&quot; invoice template open in Word for Mac. It looks like a finished invoice with sample values (Sample Customer Ltd, Sample item, 1, £100.00), and Word's comment pane down the right holds tags such as {{#each lines}}, {{item}} and {{customer.name}}." style="display:block;margin:0 auto" />

<p>Both templates render the same invoice from the same data:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/bc37df37-0da7-4977-86da-8ac61514c236.png" alt="The rendered invoice: INV-2026-0142 for Placeholder Studio Ltd, overdue, three lines totalling £2,850.00, VAT at 20% of £570.00, £3,420.00 due, and a QR code to pay online." style="display:block;margin:0 auto" />

<p>But I know which template I'd rather maintain.</p>
<p>These are the ten things that made the difference.</p>
<h2>1. Put the tags in comments</h2>
<p>Instead of typing <code>{{customer.name}}</code> into the page, you can type a realistic placeholder value, "Sample Customer Ltd", select it, and add a Word comment holding the tag. When ETCH renders the template, the selected text is replaced by the value, the value keeps the sample's formatting, and the comment is removed.</p>
<p>The template now looks much more like the document it would produce, so the layout you see is the layout you get. Anyone can read it, including people who've never seen a tag. And the formatting is applied to ordinary text, so it looks more natural.</p>
<p>It works on more than a word or two. A comment on a whole table row holding <code>{{#each lines}}</code> repeats the row once for each line, and comments on the cells inside it say what goes in each cell. A comment on a paragraph holding <code>{{#if invoice.overdue}}</code> shows or hides the whole paragraph.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/e9c14f2e-1bf6-4de8-85c5-8ea72d95ff3c.png" alt="Close-up of the &quot;after&quot; template in Word: the line-items table's one sample row (Sample item, 1, £100.00, £100.00), with Word's comments beside it holding {{item}}, {{qty}}, {{unit_price | currency &quot;£&quot;}}, {{amount | currency &quot;£&quot;}} and {{#each lines}}." style="display:block;margin:0 auto" />

<p>Excel works the same way, with a comment or a note on a cell, and so does PowerPoint, on text, pictures, charts and tables etc. Typed tags still work, and the two mix freely. In this invoice I've typed the short ones and used comments where the sample text matters.</p>
<h2>2. Calculate it once with <code>{{#var}}</code></h2>
<p>The "before" template calculates the total three times. With <code>{{#var}}</code> it's calculated once, at the top, and each variable can build on the ones before it:</p>
<pre><code class="language-handlebars">{{#var subtotal (sum lines "amount")}}{{#var vat $subtotal * vat_rate}}{{#var total $subtotal + $vat}}
</code></pre>
<p>Everywhere else the total is just specified as <code>{{$total | currency "£"}}</code>. If the calculation changes, there's one place to change it, and the tags that use it are short enough to read.</p>
<p>One thing to know: a variable is worked out once, where you define it. If you need a different value on every row of a table, you can define it inside the loop.</p>
<h2>3. Write it once with <code>{{#define}}</code></h2>
<p>The billing and delivery addresses are the same shape in the JSON, so they're defined once, as a snippet with a parameter:</p>
<pre><code class="language-handlebars">{{#define address(a)}}
{{a.line1}}
{{a.city}} {{a.postcode}}
{{/define}}
</code></pre>
<p>Each address in the invoice is then one short tag, <code>{{&gt; address(customer.billing)}}</code> and <code>{{&gt; address(customer.delivery)}}</code>. The definition doesn't appear in the output.</p>
<p>You can even apply formatting and styling to the <code>{{#define}}</code>...<code>{{/define}}</code> block and it will be retained in the output!</p>
<h2>4. Shorter paths with <code>{{#with}}</code></h2>
<p>Long paths make every tag longer than it needs to be. <code>{{#with}}</code> sets where the paths start for a block, so the line under the invoice's title reads:</p>
<pre><code class="language-handlebars">{{#with invoice}}Invoice {{number}} · Issued {{date | date "D MMMM YYYY"}} · Due {{due | date "D MMMM YYYY"}}{{/with}}
</code></pre>
<p>so instead of having to use <code>{{invoice.number}}</code> and <code>{{invoice.due}}</code> we can use the <code>{{#with invoice}}</code> and now when we reference <code>{{number}}</code> and <code>{{due}}</code> ETCH knows we are referencing the <code>invoice</code> element. You can also use <code>{{#root &lt;object&gt;}}</code> at the document level too if you want to just use a deeply nested object of your JSON</p>
<h2>5. Define a style with <code>{{#format}}</code></h2>
<p>When a tag has to be typed into running text, it's tempting to style the tag itself to match the output, which is how the red bold tags in the "before" template were done. <code>{{#format}}</code> lets you style a sample once and give it a name:</p>
<pre><code class="language-handlebars">{{#format money}}£0.00{{/format}}
</code></pre>
<p>That definition is bold in the template, and the format tag itself is removed from the output. Then <code>{{$total | currency "£" | format money}}</code> anywhere in the document comes out bold.<br /><br />This lets you define styles once in your template and reuse them while maintaining a central place for any changes.</p>
<h2>6. Pictures and charts: lay them out, and bind them with Alt Text</h2>
<p>A picture that comes from your data, like the QR code on the invoice, doesn't need a tag on the page at all. Insert any placeholder picture, size and position it where you want it, and put the tag in its Alt Text:</p>
<pre><code class="language-handlebars">{{#qr invoice.pay_url}}QR code to pay invoice {{invoice.number}} online
</code></pre>
<p>ETCH swaps the picture and keeps the size, position and crop you gave it. The text after the tag becomes the picture's real Alt Text in the output, so the document is accessible as well.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/18fdf23b-738b-4a3b-98b2-5bad91e36e30.png" alt="Word's Alt Text pane open on the placeholder QR picture in the &quot;after&quot; template, holding {{#qr invoice.pay_url}}QR code to pay invoice {{invoice.number}} online." style="display:block;margin:0 auto" />

<p>Charts work the same way. Draw and style a chart in PowerPoint (or Word) with dummy data, and put <code>{{#chart regions x="region" y="sales"}}</code> in its Alt Text. ETCH replaces the chart's data and leaves its design exactly how you designed it. In Excel the same tag writes the rows into the chart's source cells, so the chart stays linked to cells you can still see and edit.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/f8f57b02-3974-4b22-8b23-022cbf94415d.png" alt="A PowerPoint slide titled &quot;Sales by region, {{quarter}}&quot; with a blue column chart of three dummy regions, and the Alt Text pane open on the chart holding {{#chart regions x=&quot;region&quot; y=&quot;sales&quot;}}Column chart of sales by region." style="display:block;margin:0 auto" />

<h2>7. Leave a note to your future self with <code>{{!-- --}}</code></h2>
<p>The most useful thing in a template six months later is a note from whoever built it. A template comment, <code>{{! … }}</code> or <code>{{!-- … --}}</code> for a multiline longer one, is removed from the output and nothing inside it is evaluated:</p>
<pre><code class="language-handlebars">{{!-- Totals are worked out once, in the variables after this note. Addresses use the address snippet. --}}
</code></pre>
<p>The long form is the one to use when the note itself mentions a tag, as in <code>{{!-- see {{customer.name}} --}}</code>, because the short form ends at the first <code>}}</code>.</p>
<h2>8. Exclude a whole section with <code>{{#exclude}}</code></h2>
<p>For more than a line, <code>{{#exclude}}</code> hides everything up to <code>{{#include}}</code>, or to the end of the document if there isn't an <code>{{#include}}</code> tag. I use it for a "notes for whoever edits this next" section at the end of the template, with a worked example or a list of the fields the data has.</p>
<p>In Excel it does something much more interesting: <code>{{#exclude}}</code> anywhere on a worksheet leaves that whole sheet out of the workbook. So the notes can live on their own sheet, next to the sheet they describe.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/08b4f7e8-89e5-45e3-baee-40b3bd40489d.png" alt="The invoice-lines workbook in Excel for Mac, on its Notes sheet: {{#exclude}} in A1 and three lines of notes for the next editor, with the Invoice lines sheet tab beside it." style="display:block;margin:0 auto" />

<h2>9. Check it before you save it with <code>etch validate</code></h2>
<p>Editing a template you didn't write, or don't remember writing, is exactly when a typo can sneak in. The <code>etch validate</code> CLI command checks a Word, Excel or PowerPoint template for split tags, blocks that don't close, and, given some sample data, paths that aren't in the data:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/781e71b4-34b4-4950-a004-a8db2702e183.png" alt="A terminal running etch validate -t invoice-edited.docx -d ../data/invoice.json, reporting three errors: {{/with} closes with a single        brace, an unclosed with tag, and invoice.numbr not found in the data." style="display:block;margin:0 auto" />

<h2>10. Live reload the results as you edit the template</h2>
<p>This is one of my favourites.</p>
<p>The <code>etch watch</code> CLI command live reloads a rendered copy of the template output and re-renders it again every time you save:</p>
<pre><code class="language-bash">etch watch -t invoice-after.docx -d invoice.json
</code></pre>
<p>It runs the same validation first, and when there's an error the preview opens as your template with a comment on the error. With comments in the template, it's where you check that the layout you designed around the sample values still looks right with the real data.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/aaa8345f-b90d-46e9-9a33-f40bdcce81f3.png" alt="Two Word for Mac windows: the &quot;after&quot; template with its comments on the left, and on the right its read-only etch watch preview showing the        finished invoice for Placeholder Studio Ltd." style="display:block;margin:0 auto" />

<p>The ETCH add-in for Office also does a similar job. It shows the fields in your data and lets you easily insert tags and data elements, then validates the template and previews the value each tag will get. There's a <a href="https://youtu.be/aU5iARp9GfE">five-minute video of it</a>.</p>
<h2>It's still a template</h2>
<p>None of this makes a complicated document simple. An invoice with three kinds of discount and a different layout for every country will have a complicated template, whatever you build it with. What these features do is put the complexity somewhere you can find it: calculations at the top, repeated blocks in one place, notes next to the things they explain, and a page that looks like the document it generates.</p>
<p><code>etch validate</code> and <code>etch watch</code> come with the ETCH CLI, which is on the Professional plan. The add-in inserts, validates and previews on any plan, and generating from it needs Standard. The tags themselves work whichever way you call ETCH: from APEX, Python, JavaScript, Go, Java or the CLI.</p>
<p>If you build document templates, in ETCH or anything else, I'd like to know what makes yours difficult to come back to. Leave a comment and let me know!</p>
]]></content:encoded></item><item><title><![CDATA[Installing ETCH in Oracle APEX in less than 5 minutes]]></title><description><![CDATA[Installing ETCH in Oracle APEX and generate Word, PowerPoint and Excel documents in minutes.]]></description><link>https://get-etch.hashnode.dev/installing-etch-in-oracle-apex-in-less-than-5-minutes</link><guid isPermaLink="true">https://get-etch.hashnode.dev/installing-etch-in-oracle-apex-in-less-than-5-minutes</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[.docx]]></category><category><![CDATA[pptx]]></category><category><![CDATA[xlsx]]></category><category><![CDATA[Document Generation]]></category><dc:creator><![CDATA[John Scott]]></dc:creator><pubDate>Tue, 27 Oct 2026 09:45:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/e8153d7d-810a-4633-a294-7bbb70983943.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most of the APEX teams and companies I've worked with over the years have the same request sooner or later: the report on screen is fine, but can I have it as a Word document? Or Excel, PowerPoint or a PDF for the customer.</p>
<p>I've heard that so many times and it's a big part of why I built <a href="https://get-etch.app">ETCH</a>. There are of course some other solutions to the problem, but ETCH tries to bridge the gap between simplicity and ultimate flexibility in some unique ways which I'll cover in more detail in later posts.</p>
<p>This post covers installing ETCH into APEX from scratch. I created a new workspace and schema for it, with a small Orders application, so every step here is from a working installation. By the end, the Orders report has a <strong>Download report</strong> entry in its Actions menu that turns the report, as the user has filtered it, into a Word document.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/ec4cd9e9-2777-4630-97f7-4d37f8b59525.png" alt=" The Orders report running in APEX, with a filter and a highlight on, three rows ticked, and the Actions menu open at &quot;Download report&quot;" style="display:block;margin:0 auto" />

<h2>Before you start</h2>
<p>You need three things (sign up for a free <a href="https://get-etch.app">ETCH</a> account to test it out):</p>
<ul>
<li><strong>The release zip for your APEX version</strong>, from the downloads area on <a href="https://get-etch.app">get-etch.app</a> once you're signed in. There's one zip per APEX version, because plugin exports only import into the version they were built for: take the highest one at or below yours. I'm on APEX 26.1, I'm using <code>etch-apex-client-26.1-v26.10.17.3.zip</code>.</li>
<li><strong>An API key</strong>, from the API keys page of the same dashboard.</li>
<li><strong>SQLcl</strong> (or SQL*Plus), and potentially a DBA for one step if your network ACLs need configured</li>
</ul>
<p><em><strong>The free plan includes the APEX plugin</strong></em>, so you can do all this to test it out yourself.</p>
<p>Unzip the release into a folder.</p>
<h2>1. The DBA check (optional if ACLs are already configured)</h2>
<p>ETCH calls the ETCH server from the database, so the parsing schema needs a network ACL for <code>api.get-etch.app</code>. The zip has a script that checks that, and the grants, for a schema you name. It doesn't change anything: it prints the SQL for whatever's missing. Your DBA runs it as SYS or another DBA account, before or after the install:</p>
<pre><code class="language-sql">@etch_dba_setup.sql DEMO
</code></pre>
<p>![SQLcl running @etch_dba_setup.sql DEMO: APEX schema APEX_260100 found; ETCH not installed in DEMO yet; the grants CREATE SESSION, TABLE, PROCEDURE, SEQUENCE and the quota all OK; under Network ACL, a [MISS] for DEMO followed by a ready-to-run DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE block, and OK for the APEX schema; "1 issue(s) found".](<a href="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/addb9d28-11a9-4f35-b8e8-25f5613978d7.gif">https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/addb9d28-11a9-4f35-b8e8-25f5613978d7.gif</a> align="center")</p>
<p>The only thing missing for my new schema was the ACL. The DBA runs the block it printed, which for me was:</p>
<pre><code class="language-sql">BEGIN
  DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
    host =&gt; 'api.get-etch.app',
    ace  =&gt; xs$ace_type(
      privilege_list =&gt; xs$name_list('connect', 'resolve'),
      principal_name =&gt; 'DEMO',
      principal_type =&gt; xs_acl.ptype_db));
END;
/
</code></pre>
<p>Your output may list more, such as a grant, or the ACL for the APEX schema itself. Run what yours prints.</p>
<h2>2. Install the packages</h2>
<p>Connect as the APEX parsing schema and run the install script:</p>
<pre><code class="language-sql">@install.sql
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/4a23905f-5ed9-4505-8149-32c0feea40c3.gif" alt="The end of @install.sql in SQLcl: the four ETCH package specifications and bodies compiled, &quot;All ETCH packages compiled successfully.&quot;, &quot;PL/SQL packages installed.&quot;, and a list of next steps: run preflight.sql, import the three plugins, configure the plugin settings." style="display:block;margin:0 auto" />

<p>It creates a small <code>ETCH_LOG</code> table and compiles four packages. It's safe to run again when you upgrade.</p>
<h2>3. Check it can reach the ETCH Server</h2>
<pre><code class="language-sql">@preflight.sql
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/20e78e15-9209-4daa-a79b-ac6afd5aa6f5.gif" alt="@preflight.sql as DEMO: server URL https://api.get-etch.app, schema DEMO, Database Oracle 23.0, APEX 26.1.0; UTL_HTTP and APEX_WEB_SERVICE accessible; &quot;ETCH server responding (version v26.10.154)&quot;; a warning that no API key was provided so the authentication check was skipped; &quot;Result: ALL CHECKS PASSED&quot;." style="display:block;margin:0 auto" />

<p>Everything passes. The one warning is about the API key (you don't need to worry about it, it's only if you want enhanced debugging).</p>
<h2>4. Configure the API key in a Web Credential (Recommended)</h2>
<p>You could paste the key into the plugin's settings, but then it's stored in the application and would be included with every export of it. A Web Credential keeps it secure, and APEX can be configured to only send it to the URLs you allow.</p>
<p>In Shared Components, open <strong>Credentials</strong> (it takes you to Workspace Utilities &gt; Web Credentials) and create one:</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>Name</td>
<td>anything, such as <code>ETCH API key</code></td>
</tr>
<tr>
<td>Static ID</td>
<td><code>etch_api_key</code></td>
</tr>
<tr>
<td>Authentication Type</td>
<td>HTTP Header</td>
</tr>
<tr>
<td>Credential Name</td>
<td><code>x-etch-api-key</code>, exactly</td>
</tr>
<tr>
<td>Credential Secret</td>
<td>your API key</td>
</tr>
<tr>
<td>Valid for URLs</td>
<td><code>https://api.get-etch.app</code></td>
</tr>
</tbody></table>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/37e93d65-53f1-4a98-8f06-96f670bfbda8.png" alt="The Web Credentials form filled in: Name &quot;ETCH API key&quot;, Static ID etch_api_key, Authentication Type HTTP Header, Credential Name x-etch-api-key, the Credential Secret shown only as dots, and Valid for URLs https://api.get-etch.app." style="display:block;margin:0 auto" />

<h2>5. Import the plugins</h2>
<p>The zip's <code>plugins</code> folder has three files. Import each one in <strong>Shared Components &gt; Plug-ins &gt; Import</strong>, with File Type set to Plug-in:</p>
<ul>
<li><code>dynamic_action_plugin_etch_dynamic_action_plugin.sql</code>,</li>
<li><code>process_type_plugin_etch_process_plugin.sql</code>,</li>
<li><code>dynamic_action_plugin_etch_helper_plugin.sql</code></li>
</ul>
<p>Which Plugin you use depends on your exact requirements, the Dynamic Action plugin is suitable for 99% of user interaction related processing, the Process Type plugin can be used whenever the Dynamic Action plugin isn't suitable (you will almost always want to also use the ETCH Helper Plugin whenever you use the Process type plugin, it's not required for the Dynamic Action plugin). We'll cover this in a later post.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/704d586a-f88c-4ac0-a14d-ca7d1c68aa7e.png" alt="The APEX Import page with dynamic_action_plugin_etch_dynamic_action_plugin.sql (754.58 KB) chosen and File Type set to Plug-in." style="display:block;margin:0 auto" />

<p>After the dynamic action plugin imports, APEX opens its Component Settings. Leave <strong>ETCH Server URL</strong> as <code>https://api.get-etch.app</code>, leave <strong>API Key</strong> empty, and put the credential's Static ID, <code>etch_api_key</code>, in <strong>API Key Web Credential</strong>. Do the same for the process plugin, because each plugin keeps its own component level settings. The helper plugin has nothing to set.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/e0074cb7-3b56-4ab5-bc64-d66e97e2f0c7.png" alt="The ETCH Dynamic Action Plugin's Component Settings after import: ETCH Server URL https://api.get-etch.app, API Key empty, API Key Web Credential etch_api_key, Undefined Variables Handling Keep Tag, Smart Report Image Embedding Yes, Batch Download ZIP File, Use Multipart No." style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/cc93a47b-7add-484e-b6f1-c716867419b2.png" alt="Shared Components &gt; Plug-ins listing the three: ETCH Dynamic Action Plugin, ETCH Helper Plugin and ETCH Process Plugin, all version 26.10.17.3." style="display:block;margin:0 auto" />

<h2>6. Create your first template</h2>
<p>The template is an ordinary Word document (but it could be Excel or PowerPoint). Mine has a heading, a line that says when it was printed, and one tag that stands for the whole report:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/62341bc9-2d47-4a2e-8abc-f341885b3313.png" alt="The template orders-report.docx open in Word: the heading &quot;Orders report&quot;, &quot;Printed {{etch.date}}&quot; and {{#apex_region       &quot;rgnOrders&quot;}}" style="display:block;margin:0 auto" />

<p><code>{{#apex_region "rgnOrders"}}</code> is replaced by the Interactive Report with that HTML DOM ID, with the user's columns, filters, highlights and sort, as they're set on screen at the time. I uploaded the file to <strong>Shared Components &gt; Static Application Files</strong>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/57e2d81e-f676-47f8-90e3-6fe270312c40.png" alt="Static Application Files with orders-report.docx added, reference #APP_FILES#orders-report.docx, beside the app's icon files." style="display:block;margin:0 auto" />

<h2>7. The dynamic action</h2>
<p>The plugin finds the report by its HTML DOM ID (or Static ID in versions of APEX prior to 26.1), so in Page Designer I gave the Orders region one, under Advanced:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/cd3e4683-73ca-4c66-ab9a-45b7a64dc30f.png" alt="Page Designer's property editor for the Orders region, with HTML DOM ID set to rgnOrders under Advanced." style="display:block;margin:0 auto" />

<p>Then a dynamic action on <strong>Page Load</strong>, with one True action of type <strong>ETCH Dynamic Action Plugin</strong>. With <em>Generate on trigger</em> unticked, Page Load itself makes no document: the action just puts its entry in the report's Actions menu when the page renders, and the document is made when someone picks it. These are its settings:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/1d105088-6d8e-4a11-9f4e-9169a2318c0d.png" alt="The ETCH action's settings in Page Designer: Name &quot;Download report&quot;; Template Source Application Static File, Static File Name orders-report.docx; Data Source Type Region(s), Region Static ID(s) rgnOrders, Rows to Export &quot;Selected Rows, else All&quot;; Output Format Word Document, Output Filename orders-{{etch.date:YYYYMMDD}}-{{etch.user}}, Output Mode Download; Add to Report Menu with only Actions Menu ticked, and Menu Label &quot;Download report&quot;." style="display:block;margin:0 auto" />

<ul>
<li><strong>Template:</strong> Application Static File, <code>orders-report.docx</code>.</li>
<li><strong>Data:</strong> Region(s), with <code>rgnOrders</code> as the Region Static ID. <strong>Rows to Export</strong> is <em>Selected Rows, else All</em>: if the user has ticked rows, only those go in. That needs the report's row selector, which this report has.</li>
<li><strong>Output:</strong> Word, downloaded, named <code>orders-{{etch.date:YYYYMMDD}}-{{etch.user}}</code>, so the file name carries the date and who made it.</li>
<li><strong>Report Menu:</strong> <em>Actions Menu</em> ticked, <em>Generate on trigger</em> unticked, and the label <em>Download report</em>.</li>
</ul>
<p>Save the page, and that's the setup done.</p>
<h2>Run it</h2>
<p>On the running page I filtered out the delivered orders, left the Overdue highlight on, ticked three rows, and chose <strong>Actions &gt; Download report</strong> (the first screenshot in this post). Word opened this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92eb45048a85288a71c45/f51a1781-b82e-4e17-8240-8d52e56f9c5a.png" alt="On the left, the template orders-report.docx in Word: the heading &quot;Orders report&quot;, &quot;Printed {{etch.date}}&quot; and {{#apex_region &quot;rgnOrders&quot;}}. On the right, the document that came back: &quot;Printed October 26, 2026&quot;, an &quot;Applied Filters&quot; line with Status != 'Delivered' and the Overdue highlight rule, and a table of the three ticked orders with their product photos, the overdue Camera Tripod row highlighted in yellow." style="display:block;margin:0 auto" />

<p>The photos came from a BLOB column in the products table. The column headings, the filter and highlight lines, and the yellow row all came from the report itself, and the template only has to say where it goes. With nothing ticked, the same menu entry gives all nine filtered orders, over three pages.</p>
<h2>Where next</h2>
<p>The <a href="https://youtu.be/UMI2QA-5w50">APEX tutorial video</a> goes through the same install and then two more templates: one that puts the report under your own table style, and one with its own layout built with <code>{{#each}}</code>, with a barcode and a QR code for every order. If you'd rather see ETCH used from other Client libraries code, the ETCH blog has posts for <a href="https://get-etch.hashnode.dev/generate-word-excel-and-powerpoint-documents-from-python-using-etch">Python</a> and <a href="https://get-etch.hashnode.dev/generate-word-excel-and-powerpoint-documents-from-node-js-using-etch">Node.js</a>, and the <a href="https://get-etch.app/docs">docs</a> cover the rest.</p>
]]></content:encoded></item><item><title><![CDATA[Generate Word, Excel and PowerPoint documents from Node.js using ETCH]]></title><description><![CDATA[Install ETCH's JavaScript client and turn your data into Word, Excel, PowerPoint and PDF files from templates you design in Office.]]></description><link>https://get-etch.hashnode.dev/generate-word-excel-and-powerpoint-documents-from-node-js-using-etch</link><guid isPermaLink="true">https://get-etch.hashnode.dev/generate-word-excel-and-powerpoint-documents-from-node-js-using-etch</guid><dc:creator><![CDATA[get-etch.app]]></dc:creator><pubDate>Mon, 26 Oct 2026 14:48:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/8eb53a1b-8176-4398-ae29-47e4c33d53ca.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Using <a href="https://get-etch.app/?utm_source=hashnode&amp;utm_medium=blog&amp;utm_campaign=javascript-office-docs&amp;utm_content=intro">ETCH</a> with JavaScript and Node.js to generate Word, Excel and PowerPoint documents is very straightforward. In this post we'll walk through the initial installation and some simple examples.</p>
<p>Everything covered here is also available in our <a href="https://github.com/etch-labs/etch-client-examples/tree/main/javascript">examples repository</a>, so you can clone it and run each one yourself.</p>
<h2>Before you start</h2>
<p>You need Node.js 22 or later, and an ETCH account. The free plan is enough for everything in this post. From the dashboard you need two things:</p>
<ul>
<li>a <strong>package token</strong>, from the Integrations page, so your package manager can download the client;</li>
<li>an <strong>API key</strong>, from the API keys page, which your code uses to call ETCH.</li>
</ul>
<p>The client is published via the ETCH package registry rather than <a href="http://npmjs.com">npmjs.com</a>. Make a project:</p>
<pre><code class="language-bash">mkdir etch-hello
cd etch-hello
npm init -y
</code></pre>
<p>Then create a file called <code>.npmrc</code> in the project folder, with these two lines:</p>
<pre><code class="language-ini">@get-etch:registry=https://packages.get-etch.app/npm/
//packages.get-etch.app/npm/:_authToken=${ETCH_TOKEN}
</code></pre>
<p>The first line means npm fetches only <code>@get-etch</code> packages from the ETCH registry and everything else from <a href="http://npmjs.com">npmjs.com</a> as usual. The second reads your token from the <code>ETCH_TOKEN</code> environment variable. Then give npm your token and install:</p>
<pre><code class="language-bash">export ETCH_TOKEN=&lt;your package token&gt;
npm install @get-etch/etch-client
</code></pre>
<p>The token stays in your environment and isn't written to any file in the project. If you use pnpm, Yarn or Windows, the <a href="https://github.com/etch-labs/etch-client-examples/blob/main/javascript/INSTALL.md">install guide</a> has the commands.</p>
<p>Finally, set your API key:</p>
<pre><code class="language-bash">export ETCH_API_KEY=&lt;your API key&gt;
</code></pre>
<h2>Your first document</h2>
<p>Here's the whole program for the first example. It reads the data from a JSON file and renders an invoice template:</p>
<pre><code class="language-javascript">import { readFile } from 'node:fs/promises';
import { ETCHClient } from '@get-etch/etch-client';

const data = JSON.parse(await readFile('invoice.json', 'utf8'));

const client = new ETCHClient(); // reads ETCH_API_KEY
const result = await client.process({ template: 'invoice.docx', data });

await result.saveToFile(`invoice-${data.number}.docx`);
</code></pre>
<p>Save it as <code>render.mjs</code>, run it with <code>node render.mjs</code>, and you get a Word document. On the left is the template, an ordinary Word file; on the right is what came back:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/3a2efb09-2bc7-45d1-90f6-9d57413afb6a.png" alt="Two invoices side by side. On the left, &quot;The template (invoice.docx, in Word)&quot;: a teal-branded invoice whose fields are tags such as {{seller.name}}, {{number}}, {{customer.name}}, a line items row starting {{#each items}}{{description}}, and {{total | currency &quot;$&quot;}}. On the right, &quot;What ETCH produced (from invoice.json)&quot;: the same invoice filled in for Kwame Placeholder, number DEMO-0001, with three line items and a total of $2,419.20." style="display:block;margin:0 auto" />

<p>Each tag names a field in the data. <code>{{customer.name}}</code> becomes "Kwame Placeholder", and <code>{{unitPrice | currency "$"}}</code> formats a number as money. The line items row starts with <code>{{#each items}}</code> and ends with <code>{{/each}}</code>, so it's repeated once for each item. The fonts, colours and spacing all come from the template, so if someone wants the invoice to look different, they change the Word file and the code stays as it is.</p>
<p>The data doesn't have to come from a file, so you can build it from a database query or an API response or a URL etc.</p>
<p>Using TypeScript? The types come with the client.</p>
<h2>Adding a logo</h2>
<p>Let's add a picture into the data, as a <code>data:</code> URI. The client has a helper that makes one from a file:</p>
<pre><code class="language-javascript">import { ETCHClient, imageFromFile } from '@get-etch/etch-client';

data.logo = await imageFromFile('images/logo.png');
</code></pre>
<p>In the template, <code>{{#image logo width="56"}}</code> marks where it goes and how wide it is. Each customer's documents could carry their own logo this way, from the same template.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/8ab6b266-c597-48fb-a659-a7d02c139b2d.png" alt="The invoice template with the tag {{#image logo width=&quot;56&quot;}} at the top, beside the finished invoice with the teal Mei Example Design logo in its place." style="display:block;margin:0 auto" />

<h2>QR codes and barcodes</h2>
<p>You can generate QR codes and barcodes from the data too. The shipping label example uses three tags:</p>
<pre><code class="language-text">{{#barcode type="code128" width="340" height="80" shipment.tracking}}
{{#qr shipment.trackingUrl size="110"}}
{{#barcode type="ean13" width="190" height="60" ean}}
</code></pre>
<p>The first draws the tracking number as a Code 128 barcode, the second a QR code of the tracking page's address, and the third, inside the packing slip's loop, an EAN-13 barcode for each product. The JavaScript code is the same as for the invoice. Only the template and the data have changed.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/b70f2010-7699-4cbb-b297-6aeef9d53e02.png" alt="A shipping label and packing slip. On the left, the template: tags for the sender, recipient and postcode, {{#barcode type=&quot;code128&quot; width=&quot;340&quot; height=&quot;80&quot; shipment.tracking}}, {{#qr shipment.trackingUrl size=&quot;110&quot;}}, and a packing slip row with an EAN-13 barcode tag. On the right, the finished label: NEXT DAY, 1.4 kg, Example Client Ltd at ZZ99 2BB, a Code 128 barcode of SMP-QX-0815001, a QR code, and a packing slip with a barcode for each of three products." style="display:block;margin:0 auto" />

<h2>Excel</h2>
<p>To generate a workbook, use an Excel template.</p>
<p>The sales workbook has a summary row with <code>{{#each regions}}</code> at the start and <code>{{/each}}</code> at the end, which becomes one row per region. The total underneath is an ordinary Excel formula, <code>=SUM(C5:C5)</code>, and ETCH stretches it to cover the new rows. The chart beside it was drawn in Excel over that same row, and its ranges grow in the same way, so it shows a bar for every region. A second sheet, marked with <code>{{#sheet-each regions}}</code>, is copied once per region and named after the region.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/d6d6a4b3-7d57-42cc-8ecf-03475b0ba052.png" alt="Two versions of the Summary sheet, one above the other. Above, the template: &quot;Monthly sales&quot; with {{company}}, {{period}} under it, a table with one row of tags, {{#each regions}}{{name}}, {{length orders}} and {{sum orders &quot;amount&quot;}}{{/each}}, a Total row, and an empty bar chart titled &quot;Sales by region&quot; whose only category is {{#each regions}}{{name}}. Below, what ETCH produced: the table lists East (3 orders, £3,755.00), North (2, £2,190.00), South (2, £2,090.50) and West (3, £3,885.00), with a total of 10 orders and £11,920.50, and the chart has an ochre bar for each region." style="display:block;margin:0 auto" />

<p>The numbers become native Excel numbers, so the formulas and number formats in the template still work with them.</p>
<h2>PowerPoint</h2>
<p>The project update deck has three slides in the template, and the finished deck has five. The middle slide starts with <code>{{#slide-each projects}}</code>, so ETCH makes a copy of it for each project, and the milestones on each slide come from a loop of their own.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/0b806a0a-b4cc-48df-96cd-ed232d01a6d5.png" alt="On the left, one template slide from project-update.pptx: {{#slide-each projects}} above {{name}}, a large {{progress | percentage}} at the top right, a card with {{owner}}, the due date and a grey pill reading {{#fill statusColor}}{{status}}, and a milestones loop. On the right, the three slides ETCH made from it: Website refresh (70.0%, a green &quot;On track&quot; pill), Customer portal (35.0%, a red &quot;At risk&quot; pill and &quot;See the speaker notes&quot;) and Brand guidelines (90.0%, green), each with its own milestones." style="display:block;margin:0 auto" />

<p>The status colour comes from the data. Each project has a <code>statusColor</code> such as <code>C0392B</code>, and the pill's text starts with <code>{{#fill statusColor}}</code>, which fills the shape with that colour. The same goes for the table cells on the summary slide.</p>
<p>The chart on the summary slide is one I drew and styled in PowerPoint with placeholder figures. Its Alt Text holds <code>{{#chart projects x="name" y="progress"}}</code>, so ETCH replaces the placeholder bars with one per project and keeps the colours and labels I gave it. The tag is easy to miss when you open the template, because it isn't on the slide. To see it, right-click the chart and choose View Alt Text.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/b8a82164-03ee-476e-b653-6370b0912b42.png" alt="The summary slide's chart open in PowerPoint, with three placeholder bars, Project A, B and C, at 50% each. Beside it, PowerPoint's Alt Text pane, whose text box reads {{#chart projects x=&quot;name&quot; y=&quot;progress&quot;}} and, on the next line, Progress by project." style="display:block;margin:0 auto" />

<p>Anything after the tag is kept as the finished chart's Alt Text, so in the deck ETCH produces, a screen reader still hears "Progress by project".</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/d21922c8-1dfa-4cec-b3e8-4885a12e5923.png" alt="The summary slide. On the left, the template: a table row loop with a grey status cell holding {{#fill statusColor}}{{status}}, and a bar chart with three placeholder bars, Project A, B and C, all at 50%. On the right, the finished slide: three projects with green, red and green status cells, and the chart showing Website refresh at 70%, Customer portal at 35% and Brand guidelines at 90%." style="display:block;margin:0 auto" />

<h2>PDF and multiple documents at once</h2>
<p>You can easily change the output format to PDF by adding <code>outputFormat</code> to the request:</p>
<pre><code class="language-javascript">const pdf = await client.process({
  template: 'invoice.docx',
  data,
  outputFormat: 'pdf',
});
</code></pre>
<p>And when you have multiple records, such as a month of invoice data, you can send them in one request. The batch template starts with <code>{{#document-each invoices filename="invoice-{{number}}.docx"}}</code>, and <code>renderBatch</code> returns one document per invoice:</p>
<pre><code class="language-javascript">const result = await client.renderBatch({ template: 'invoice-batch.docx', data });

console.log(`Rendered ${result.succeeded} of ${result.total} invoices`);
await result.saveAll('output/invoices');
await result.saveArchive('output/invoices.zip');
</code></pre>
<p>If one record has a problem, it will fail in isolation, and <code>result.failures</code> tells you which one failed. The other documents still come back.</p>
<h2>Where to go next</h2>
<p>The <a href="https://github.com/etch-labs/etch-client-examples/tree/main/javascript">JavaScript examples</a> have 28 of these, each with a README. They cover conditionals, formatters, helpers that add up and rank figures in the template, reusable blocks, stored templates, error handling and running several renders in parallel. The <a href="https://youtu.be/EW-hoAbevDs">Node.js video</a> builds the invoice template in Word from scratch, renders it from a short Node script, and then makes an Excel workbook with the same code.</p>
<p>You can <a href="https://get-etch.app/?utm_source=hashnode&amp;utm_medium=blog&amp;utm_campaign=javascript-office-docs&amp;utm_content=signup">sign up for the free plan</a>, which gives you 200 documents a month and includes the client libraries. The same examples exist for Python, which has <a href="https://get-etch.hashnode.dev/generate-word-excel-and-powerpoint-documents-from-python-using-etch">its own post</a>, and for Java, whose post is coming next.</p>
]]></content:encoded></item><item><title><![CDATA[Generate Word, Excel and PowerPoint documents from Python using ETCH]]></title><description><![CDATA[Install ETCH's Python client and turn your data into Word, Excel, PowerPoint and PDF files from templates you design in Office.]]></description><link>https://get-etch.hashnode.dev/generate-word-excel-and-powerpoint-documents-from-python-using-etch</link><guid isPermaLink="true">https://get-etch.hashnode.dev/generate-word-excel-and-powerpoint-documents-from-python-using-etch</guid><category><![CDATA[.docx]]></category><category><![CDATA[xlsx]]></category><category><![CDATA[pptx]]></category><category><![CDATA[etch]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[get-etch.app]]></dc:creator><pubDate>Mon, 26 Oct 2026 12:58:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/f27e1475-7053-496c-8b75-d7896848611a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Using <a href="https://get-etch.app/?utm_source=hashnode&amp;utm_medium=blog&amp;utm_campaign=python-office-docs&amp;utm_content=intro">ETCH</a> with Python to generate Word, Excel and PowerPoint documents is very straightforward. In this post we'll walk through the initial installation and some simple examples.</p>
<p>Everything covered here is also available in our <a href="https://github.com/etch-labs/etch-client-examples/tree/main/python">examples repository</a>, so you can clone it and run each one yourself.</p>
<h2>Before you start</h2>
<p>You need Python 3.9 or later, and an ETCH account. The free plan is enough for everything in this post. From the dashboard you need two things:</p>
<ul>
<li>a <strong>package token</strong>, from the Integrations page, so your package manager can download the client;</li>
<li>an <strong>API key</strong>, from the API keys page, which your code uses to call ETCH.</li>
</ul>
<p>The client is published via the ETCH package registry rather than PyPI. With <a href="https://docs.astral.sh/uv/">uv</a>, make a project and tell it where <code>etch-client</code> comes from:</p>
<pre><code class="language-bash">uv init etch-hello
cd etch-hello
</code></pre>
<p>Add this to the end of <code>pyproject.toml</code>:</p>
<pre><code class="language-toml">[[tool.uv.index]]
name = "etch"
url = "https://packages.get-etch.app/pypi/simple/"
explicit = true

[tool.uv.sources]
etch-client = { index = "etch" }
</code></pre>
<p><code>explicit = true</code> means uv fetches only <code>etch-client</code> from the ETCH registry and everything else from PyPI as usual. Then give uv your token and install:</p>
<pre><code class="language-bash">export UV_INDEX_ETCH_USERNAME=__token__
export UV_INDEX_ETCH_PASSWORD=&lt;your package token&gt;
uv add etch-client
</code></pre>
<p>The token stays in your environment and isn't written to any file in the project. If you use pip, or Windows, the <a href="https://github.com/etch-labs/etch-client-examples/blob/main/python/INSTALL.md">install guide</a> has the commands.</p>
<p>Finally, set your API key:</p>
<pre><code class="language-bash">export ETCH_API_KEY=&lt;your API key&gt;
</code></pre>
<h2>Your first document</h2>
<p>Here's the whole program for the first example. It reads the data from a JSON file and renders an invoice template:</p>
<pre><code class="language-python">import json
from pathlib import Path

from etch import ETCHClient

data = json.loads(Path("invoice.json").read_text(encoding="utf-8"))

with ETCHClient() as client:  # reads ETCH_API_KEY
    result = client.process({"template": "invoice.docx", "data": data})

result.save_to_file(Path(f"invoice-{data['number']}.docx"))
</code></pre>
<p>Run it with <code>uv run render.py</code>, and you get a Word document. On the left is the template, an ordinary Word file; on the right is what came back:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/3a2efb09-2bc7-45d1-90f6-9d57413afb6a.png" alt="Two invoices side by side. On the left, &quot;The template (invoice.docx, in Word)&quot;: a teal-branded invoice whose fields are tags such as {{seller.name}}, {{number}}, {{customer.name}}, a line items row starting {{#each items}}{{description}}, and {{total | currency &quot;$&quot;}}. On the right, &quot;What ETCH produced (from invoice.json)&quot;: the same invoice filled in for Kwame Placeholder, number DEMO-0001, with three line items and a total of $2,419.20." style="display:block;margin:0 auto" />

<p>Each tag names a field in the data. <code>{{customer.name}}</code> becomes "Kwame Placeholder", and <code>{{unitPrice | currency "$"}}</code> formats a number as money. The line items row starts with <code>{{#each items}}</code> and ends with <code>{{/each}}</code>, so it's repeated once for each item. The fonts, colours and spacing all come from the template, so if someone wants the invoice to look different, they change the Word file and the code stays as it is.</p>
<p>The data doesn't have to come from a file, so you can build it from a database query or an API response or a URL etc.</p>
<h2>Adding a logo</h2>
<p>Let's add a picture into the data, as a <code>data:</code> URI. The client has a helper that makes one from a file:</p>
<pre><code class="language-python">from etch import ETCHClient, image_from_file

data["logo"] = image_from_file(Path("images/logo.png"))
</code></pre>
<p>In the template, <code>{{#image logo width="56"}}</code> marks where it goes and how wide it is. Each customer's documents could carry their own logo this way, from the same template.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/8ab6b266-c597-48fb-a659-a7d02c139b2d.png" alt="The invoice template with the tag {{#image logo width=&quot;56&quot;}} at the top, beside the finished invoice with the teal Mei Example Design logo in its place." style="display:block;margin:0 auto" />

<h2>QR codes and barcodes</h2>
<p>You can generate QR codes and barcodes from the data too. The shipping label example uses three tags:</p>
<pre><code class="language-text">{{#barcode type="code128" width="340" height="80" shipment.tracking}}
{{#qr shipment.trackingUrl size="110"}}
{{#barcode type="ean13" width="190" height="60" ean}}
</code></pre>
<p>The first draws the tracking number as a Code 128 barcode, the second a QR code of the tracking page's address, and the third, inside the packing slip's loop, an EAN-13 barcode for each product. The Python code is the same as for the invoice. Only the template and the data have changed.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/b70f2010-7699-4cbb-b297-6aeef9d53e02.png" alt="A shipping label and packing slip. On the left, the template: tags for the sender, recipient and postcode, {{#barcode type=&quot;code128&quot; width=&quot;340&quot; height=&quot;80&quot; shipment.tracking}}, {{#qr shipment.trackingUrl size=&quot;110&quot;}}, and a packing slip row with an EAN-13 barcode tag. On the right, the finished label: NEXT DAY, 1.4 kg, Example Client Ltd at ZZ99 2BB, a Code 128 barcode of SMP-QX-0815001, a QR code, and a packing slip with a barcode for each of three products." style="display:block;margin:0 auto" />

<h2>Excel</h2>
<p>To generate a workbook, use an Excel template.</p>
<p>The sales workbook has a summary row with <code>{{#each regions}}</code> at the start and <code>{{/each}}</code> at the end, which becomes one row per region. The total underneath is an ordinary Excel formula, <code>=SUM(C5:C5)</code>, and ETCH stretches it to cover the new rows. The chart beside it was drawn in Excel over that same row, and its ranges grow in the same way, so it shows a bar for every region. A second sheet, marked with <code>{{#sheet-each regions}}</code>, is copied once per region and named after the region.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/d6d6a4b3-7d57-42cc-8ecf-03475b0ba052.png" alt="Two versions of the Summary sheet, one above the other. Above, the template: &quot;Monthly sales&quot; with {{company}}, {{period}} under it, a table with one row of tags, {{#each regions}}{{name}}, {{length orders}} and {{sum orders &quot;amount&quot;}}{{/each}}, a Total row, and an empty bar chart titled &quot;Sales by region&quot; whose only category is {{#each regions}}{{name}}. Below, what ETCH produced: the table lists East (3 orders, £3,755.00), North (2, £2,190.00), South (2, £2,090.50) and West (3, £3,885.00), with a total of 10 orders and £11,920.50, and the chart has an ochre bar for each region." style="display:block;margin:0 auto" />

<p>The numbers become native Excel numbers, so the formulas and number formats in the template still work with them.</p>
<h2>PowerPoint</h2>
<p>The project update deck has three slides in the template, and the finished deck has five. The middle slide starts with <code>{{#slide-each projects}}</code>, so ETCH makes a copy of it for each project, and the milestones on each slide come from a loop of their own.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/0b806a0a-b4cc-48df-96cd-ed232d01a6d5.png" alt="On the left, one template slide from project-update.pptx: {{#slide-each projects}} above {{name}}, a large {{progress | percentage}} at the top right, a card with {{owner}}, the due date and a grey pill reading {{#fill statusColor}}{{status}}, and a milestones loop. On the right, the three slides ETCH made from it: Website refresh (70.0%, a green &quot;On track&quot; pill), Customer portal (35.0%, a red &quot;At risk&quot; pill and &quot;See the speaker notes&quot;) and Brand guidelines (90.0%, green), each with its own milestones." style="display:block;margin:0 auto" />

<p>The status colour comes from the data. Each project has a <code>statusColor</code> such as <code>C0392B</code>, and the pill's text starts with <code>{{#fill statusColor}}</code>, which fills the shape with that colour. The same goes for the table cells on the summary slide.</p>
<p>The chart on the summary slide is one I drew and styled in PowerPoint with placeholder figures. Its Alt Text holds <code>{{#chart projects x="name" y="progress"}}</code>, so ETCH replaces the placeholder bars with one per project and keeps the colours and labels I gave it. The tag is easy to miss when you open the template, because it isn't on the slide. To see it, right-click the chart and choose View Alt Text.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/b8a82164-03ee-476e-b653-6370b0912b42.png" alt="The summary slide's chart open in PowerPoint, with three placeholder bars, Project A, B and C, at 50% each. Beside it, PowerPoint's Alt Text pane, whose text box reads {{#chart projects x=&quot;name&quot; y=&quot;progress&quot;}} and, on the next line, Progress by project." style="display:block;margin:0 auto" />

<p>Anything after the tag is kept as the finished chart's Alt Text, so in the deck ETCH produces, a screen reader still hears "Progress by project".</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/d21922c8-1dfa-4cec-b3e8-4885a12e5923.png" alt="The summary slide. On the left, the template: a table row loop with a grey status cell holding {{#fill statusColor}}{{status}}, and a bar chart with three placeholder bars, Project A, B and C, all at 50%. On the right, the finished slide: three projects with green, red and green status cells, and the chart showing Website refresh at 70%, Customer portal at 35% and Brand guidelines at 90%." style="display:block;margin:0 auto" />

<h2>PDF, and multiple documents at once</h2>
<p>You can easily change the output format to PDF by adding <code>output_format</code> to the request:</p>
<pre><code class="language-python">from etch import ETCHClient, OutputFormat

pdf = client.process({
    "template": "invoice.docx",
    "data": data,
    "output_format": OutputFormat.PDF,
})
</code></pre>
<p>And when you have multiple records, such as a month of invoices, you can send them in one request. The batch template starts with <code>{{#document-each invoices filename="invoice-{{number}}.docx"}}</code>, and <code>render_batch</code> returns one document per invoice:</p>
<pre><code class="language-python">with ETCHClient() as client:
    result = client.render_batch({"template": "invoice-batch.docx", "data": data})

print(f"Rendered {result.succeeded} of {result.total} invoices")
result.save_all(Path("output/invoices"))
result.save_zip(Path("output/invoices.zip"))
</code></pre>
<p>If one record has a problem, it fails in isolation, and <code>result.failures</code> tells you which one failed. The other documents still come back.</p>
<h2>Where to go next</h2>
<p>The <a href="https://github.com/etch-labs/etch-client-examples/tree/main/python">Python examples</a> have 28 of these, each with a README. They cover conditionals, formatters, helpers that add up and rank figures in the template, reusable blocks, stored templates, error handling and running several renders in parallel. The <a href="https://youtu.be/eSK2OcLYPUE">Python video</a> builds the invoice template in Word from scratch and renders it from Python, with uv and with pip.</p>
<p>You can <a href="https://get-etch.app/?utm_source=hashnode&amp;utm_medium=blog&amp;utm_campaign=python-office-docs&amp;utm_content=signup">sign up for the free plan</a>, which gives you 200 documents a month and includes the client libraries. The same examples exist for JavaScript and Java, and those posts are coming next.</p>
]]></content:encoded></item><item><title><![CDATA[What is ETCH and how can it help?]]></title><description><![CDATA[Create a document template in Office, mark where the data goes, and ETCH generates it from Oracle APEX, Python, JavaScript, Go, Java or the REST API]]></description><link>https://get-etch.hashnode.dev/what-is-etch-and-how-can-it-help</link><guid isPermaLink="true">https://get-etch.hashnode.dev/what-is-etch-and-how-can-it-help</guid><category><![CDATA[.docx]]></category><category><![CDATA[pptx]]></category><category><![CDATA[xlsx]]></category><category><![CDATA[Document Generation]]></category><category><![CDATA[Python]]></category><category><![CDATA[Java]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[get-etch.app]]></dc:creator><pubDate>Fri, 23 Oct 2026 13:48:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/97d1001c-fc71-46b7-804b-0f9d679332f3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You've probably seen a folder like this one. I've worked in plenty of places where it was normal. Every quarter, someone opens last quarter's deck, saves it under a new name, and spends a day pasting in figures from the finance system and from a spreadsheet somebody emails round. By the time it reaches the board there are six copies, and nobody is quite sure which one went out.</p>
<p>Then the messages start...</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/73d64fce-0199-4368-bb43-eb06bd6674ef.png" alt="A team chat. Priya Sample: &quot;Hey, sorry, I think the deck that went out has last quarter's figures on slide 4?&quot; Five days later, Tomás Placeholder: &quot;Finance have just updated month end. Would you mind redoing the slides before Thursday?&quot;" style="display:block;margin:0 auto" />

<h2>The two problems</h2>
<p>The first is copies of copies. The document is out of date as soon as it's created and sent out, because the data was typed in by hand. A correction to that data involves a whole lot of manual work and verification, and everyone who keeps their own copy of the spreadsheet believes theirs is the latest and greatest. There's no central source of the truth.</p>
<p>The second problem turns up when a team does automate it, often the output document layout is baked into the program to generate it. So whenever the document needs to be changed it results in code needing to be changed and all the overhead and time that comes with that process.</p>
<h2>How ETCH Helps</h2>
<p><a href="https://get-etch.app">ETCH</a> takes a template you design in Word, Excel, PowerPoint, Markdown or PDF and fills it with your data as JSON, and outputs the finished document in exactly the style you defined.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/41ea5b57-b159-40bf-ad00-fcbb00d183c4.png" alt="A diagram: a template, your data as JSON, and the client libraries all lead into ETCH, which produces a PowerPoint deck, a Word summary, an Excel workbook and a PDF." style="display:block;margin:0 auto" />

<p>The template is an ordinary Office file, where you want data to appear you type a tag such as <code>{{kpis.revenue}}</code>, and you style it however you like. The formatting and layout you give to the template is the formatting the finished document will have.</p>
<p>Keeping the template and data separate pays off in both directions, where the template needs to be changed you don't need to change any code and vice-versa you are free to modify the code to change how the processing happens without having to worry about the document itself changing.</p>
<p>The data can be a JSON file, or your own code can build it dynamically or fetch it from a URL. In Oracle APEX it can come straight from a SQL query or an interactive report, interactive grid, chart or anywhere else.</p>
<h2>A worked example: the quarterly deck</h2>
<p>To show it properly, I built the deck from that folder: a five-slide board report for a made-up company, Placeholder Trading Ltd. Every figure in it is invented.</p>
<p>Here's slide 4, the one the message said had last quarter's figures. On the left is the template; on the right is what ETCH generated from the Q1 data.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/5cd8bfd6-eff7-4556-b704-891ab6146198.png" alt="Slide 4, &quot;Revenue by region&quot;, as a template with tags in each table cell, beside the same slide filled in with four regions and a total of £1.28M." style="display:block;margin:0 auto" />

<p>The table row is a loop. <code>{{#each regions}}</code> repeats it once per region, <code>{{#if revenue &gt;= target}}</code> chooses between "Ahead" and "Behind", and the total underneath is <code>{{sum regions "revenue"}}</code>, added up in the template itself.</p>
<p>The data is a plain JSON file. The part slide 4 uses looks like this:</p>
<pre><code class="language-json">{
  "company": "Placeholder Trading Ltd",
  "quarter": "Q1",
  "year": 2026,
  "regions": [
    { "name": "London and South East", "revenue": 452000, "target": 430000 },
    { "name": "Midlands", "revenue": 298000, "target": 310000 },
    { "name": "North", "revenue": 341000, "target": 320000 },
    { "name": "Scotland", "revenue": 193000, "target": 190000 }
  ]
}
</code></pre>
<p>The chart on slide 3 is worth a callout, because in the template it looks like any other chart. I drew and styled it in PowerPoint with placeholder figures, and put <code>{{#chart months x="month"}}</code> in its Alt Text. ETCH replaces the months and the figures with the data, and matches the Revenue and Costs series by name, so they keep the colours and styling I gave them.</p>
<p>Next quarter, nobody needs to copy anything. Finance send a new JSON file, and the deck is made again from the same template.</p>
<h2>Workflow</h2>
<p>The quickest way to iterate on template design is using the <code>etch watch</code> command in the ETCH command line tool (available on selected plans).</p>
<p>You keep the template open in PowerPoint, and a preview beside it is refreshed each time you save the template or the data changes.</p>
<pre><code class="language-sh">etch watch -t "Q1 Quarterly Report.pptx" -d q1-figures.json --open
</code></pre>
<p>In this recording I add <code>{{quarter}}</code> to the title on slide 1 and save. Then finance's month end figures land on top of the data file, and slide 2 goes from £1.28M to £1.31M without anyone opening the deck.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ab92e30bc72733fdb544867/d7f704d6-e35c-42ef-a531-22e1de2d2e09.gif" alt="A screen recording: the PowerPoint template on the left, the deck ETCH made from it on the right, and etch watch in a terminal below. Typing {{quarter}} into the template's title turns the deck's title into &quot;Quarterly Report Q1&quot;. When the month end figures arrive, revenue on slide 2 changes from £1.28M to £1.31M." style="display:block;margin:0 auto" />

<p>On slide 2 the template holds tags such as <code>£{{kpis.revenue | compact 2}}</code> and <code>{{kpis.revenueChange | abs | percentage}}</code>, and the preview shows what they turn into.</p>
<p>Previews are normally free and carry a watermark. I recorded this one with <code>--no-watermark</code>, which renders a clean copy and counts each save as one of the month's documents. The command line tool comes with the Professional and Enterprise plans.<br /><br />To make the finished file rather than a preview:</p>
<pre><code class="language-sh">etch process -t quarterly-report.pptx -d q1-2026.json -o "Q1 Quarterly Report.pptx"
</code></pre>
<h2>Client Library Support</h2>
<h3>Oracle APEX</h3>
<p>Oracle APEX is where I've spent most of my working life, and it's where I've seen this problem most often. The ETCH plugins for APEX add a dynamic action and a page process plugin. You choose a template and the data, which can be a SQL query or an interactive report or grid, and the user gets the document in their browser. An interactive report or grid comes across with whatever filters and sorting the user has applied.</p>
<p>The <a href="https://youtu.be/UMI2QA-5w50">APEX tutorial video</a> goes through it from start to finish.</p>
<h3>Python</h3>
<pre><code class="language-python">import json
from pathlib import Path

from etch import ETCHClient

data = json.loads(Path("q1-2026.json").read_text(encoding="utf-8"))

with ETCHClient() as client:  # reads your API key from ETCH_API_KEY
    result = client.process({
        "template": "quarterly-report.pptx",
        "data": data,
    })

result.save_to_file(Path("Q1 Quarterly Report.pptx"))
</code></pre>
<p>The client installs from the ETCH package registry with the package token from your dashboard; the <a href="https://github.com/etch-labs/etch-client-examples/blob/main/python/INSTALL.md">install steps</a> cover uv and pip. There's a <a href="https://youtu.be/eSK2OcLYPUE">Python video</a> too.</p>
<h3>JavaScript and Node.js</h3>
<pre><code class="language-js">import { readFile } from 'node:fs/promises';
import { ETCHClient } from '@get-etch/etch-client';

const data = JSON.parse(await readFile('q1-2026.json', 'utf8'));

const client = new ETCHClient(); // reads your API key from ETCH_API_KEY
const result = await client.process({ template: 'quarterly-report.pptx', data });
await result.saveToFile('Q1 Quarterly Report.pptx');
</code></pre>
<p>The <a href="https://github.com/etch-labs/etch-client-examples/blob/main/javascript/INSTALL.md">install steps</a> cover npm and Yarn, and there's a <a href="https://youtu.be/EW-hoAbevDs">Node.js video</a>.</p>
<h3>Other languages</h3>
<p>We support Oracle APEX, Python, JavaScript and Node.js, Java, Go, Swift and REST API</p>
<h2>Try ETCH Today</h2>
<p>Sign up today at <a href="https://get-etch.app">https://get-etch.app</a> you can try the free plan, which gives you 200 documents a month and includes access to all the client libraries and then upgrade to whatever paid plan suits you.</p>
<p>Over the coming weeks we'll be posting a lot more about ETCH and the capabilities and features available, so follow the blog to be notified about updates.</p>
]]></content:encoded></item></channel></rss>