One template can serve many situations: include the rush clause only when the client asked for rush service, list every business owner the form collected, show a payment schedule only for recurring services. Liquid's logic tags — {% if %} and {% for %} — make your engagement letter adapt to each engagement.
Showing and hiding content with if
Wrap any content in an if block and it only appears when the condition is true:
{% if engagement.rush == "Yes" %}
Because you have requested expedited service, a rush fee of $500 will
be added to the fees described above.
{% endif %}
Add an {% else %} for the alternative, or {% elsif %} for several branches:
{% if engagement.entity_type == "LLC" %}
We will prepare and file Articles of Organization.
{% elsif engagement.entity_type == "Corporation" %}
We will prepare and file Articles of Incorporation.
{% else %}
We will advise you on the appropriate entity type before filing.
{% endif %}
{% unless %} is the mirror image — the content shows when the condition is false.
What you can test
Condition | True when… |
| the answer is exactly "Yes" |
| the answer is anything else |
| that option was among the checkbox selections |
| the client has a phone number |
| the optional signer wasn't skipped |
Combine conditions with and / or:
{% if engagement.entity_type == "LLC" and engagement.state == "Delaware" %}
Three practical rules
Compare against the label. Radio and checkbox answers print the option labels your client saw — so test against those exact labels, including capitalization:
== "Yes", not== "yes".Use straight quotes. Word and Google Docs love converting straight quotes into curly ones, which breaks the comparison. Undo the autocorrect (Ctrl/Cmd-Z right after typing) or disable smart quotes while editing.
Close every block. Each
{% if %}needs its{% endif %}— an unbalanced block stops the letter from generating, and the error will tell you which tag is unmatched.
Whole paragraphs vs. inline conditions
Both styles work:
Inline — hide part of a line:
Fee: {{ service.price | usd }}{% if service.frequency != blank %} per {{ service.frequency }}{% endif %}Whole paragraph — put
{% if %}on its own line above the content and{% endif %}on its own line below. When the condition is false, the paragraphs are removed cleanly — no stray empty lines left behind.
For multi-paragraph sections (a whole optional clause), always use the whole-paragraph style.
Repeating content with for
Loops repeat a block once per item in a list. The classic example is listing every contact on the engagement:
{% for user in users %}{{ user.name }}, {{ user.email }}
{% endfor %}
The name after for (here user) is yours to choose; use it inside the loop to refer to the current item.
Signers collected from a repeating form group ("add each business owner") work the same way — see Placing Signatures in Engagement Letters for signature loops:
{% for owner in signers.owners %}
{% signature owner %}
{% endfor %}
Differences between Word and Google Docs templates
Both formats support everything above, with two caveats for Google Docs:
Keep each tag uniformly styled. A tag like
{% if engagement.rush == "Yes" %}must be one consistent style — don't bold half of it. (Style the content between tags however you like.)Loop bodies stay within one paragraph. In Google Docs, a
{% for %}block can't span multiple paragraphs or repeat table rows. Word templates don't have this limit — and Word additionally supports repeating table rows (see Advanced Liquid).
Testing your logic
Generate a test letter for each important path — one with "Yes", one with "No" — and read the output. Conditional bugs are much easier to spot in a rendered letter than in the template.
