ESPklaviyodjango-templatingecommerceesp

How to use Draftship with Klaviyo

Klaviyo's HTML editor accepts pasted Draftship exports cleanly, but the personalization layer uses Django templating, dynamic blocks lock content, and product feeds want their own block type. Here's the path that keeps render fidelity.

HTML import path
code editor
Merge syntax
{{ first_name|default:'there' }} (Django)
Image hosting
platform CDN
Best for
Ecommerce teams running flows tied to Shopify, Magento, or BigCommerce events.
Watch out for
Drag-drop blocks lock the surrounding HTML. Use a blank HTML template to keep your Draftship layout intact.

Klaviyo dominates ecommerce email because it ties tightly to product events: Shopify checkout abandoned, viewed product, started checkout, all of it. The flip side: their email editor mixes drag-drop blocks with raw HTML, and the drag-drop blocks lock the surrounding HTML when used. If you want your Draftship export to survive intact, use a blank HTML template and add Klaviyo's dynamic features through Django syntax in the body.

Where Klaviyo accepts pasted HTML

Klaviyo offers two template types: drag-drop and HTML. Pick HTML. From your dashboard, go to Email Templates → Create Template → HTML. The full code editor opens. Paste your Draftship export.

STEP 1Design inDraftshipBlock editorSTEP 2ExportOutlook-safe HTMLCmd+ESTEP 3Klaviyo HTMLTemplateEmail Templates > NewSTEP 4Wire Djangopersonalization{{first_name|default:'there'}}STEP 5Use in Flow orCampaignSendKlaviyo handoff
Draftship to Klaviyo HTML template handoff

Django template syntax

Klaviyo uses Django's template language, not Liquid. The two look similar but the filter syntax differs. Defaults use a colon-quote pattern.

DraftshipKlaviyo
{{ first_name }}{{ first_name|default:'there' }}
{{ last_name }}{{ last_name|default:'' }}
{{ email }}{{ email }}
{{ company }}{{ properties.company|default:'' }}
Unsubscribe link{% web_view_link %} and {% unsubscribe_link %}
Profile attribute{{ person.first_name }} (in flows)

For event-driven flows (cart abandon, browse abandon), the event payload is in scope. To reference an item:

liquid
{% for item in event.extra.line_items %} <p>{{ item.product_name }}: ${{ item.price }}</p> {% endfor %}

This is Django syntax, even though it visually resembles Liquid. {% for %}, {% if %}, {% endif %} are all supported.

Dynamic content blocks (and why to avoid them in your HTML)

Klaviyo's drag-drop has a "Dynamic Content" block type that swaps content based on profile properties. They render as opaque components in the HTML editor. If you've pasted a clean Draftship export and add a dynamic block, Klaviyo wraps it in their own divs and rewrites the surrounding cells. This is the behavior to avoid.

The Django-native way is to write the conditional yourself in your pasted HTML:

liquid
{% if person.tier == 'gold' %} <p>You're a gold member. Here's your perk.</p> {% else %} <p>Welcome to our list.</p> {% endif %}

This survives every save and stays in your control.

Image hosting

Klaviyo offers an image library at Content → Images. Upload there for permanent hosting on Klaviyo's CDN. External URLs work but aren't auto-mirrored. For ecommerce stores syncing product images from Shopify, Klaviyo can reference Shopify CDN URLs directly without a re-upload.

Klaviyo's link tracking and UTM behavior

Klaviyo wraps links at send time for click tracking. It preserves your existing UTM parameters. Two things to know:

  • Tracking can be disabled per link by adding ?_kx=disable to the URL. Useful for unsubscribe and preference center links you don't want clicked-through metrics on.
  • Klaviyo's UTM defaults are configurable per account. If you've baked UTMs into your Draftship hrefs, disable Klaviyo's auto-UTM under Account Settings → UTM Tracking to avoid duplication.

Test send checklist

  • Use Send Preview with a real profile from your test list.
  • Confirm Django conditionals resolved, not the raw {% if %} blocks.
  • Open the rendered HTML in Klaviyo's preview source, copy it, and run through the size checker.
  • For Flow emails, trigger the flow with a test event before going live.

When to use Klaviyo's drag-drop instead

If your team has marketers building emails weekly without engineering support, the drag-drop is the right tool, and the lock-in tradeoff is acceptable. For high-stakes one-off campaigns, the HTML template path with Draftship gives you more control.

For UTM hygiene across ESPs, see UTM parameters for email marketers.

FAQ

Frequently asked questions

Why does Klaviyo use Django templating instead of Liquid?
Historical reasons; Klaviyo's backend was built on Python and reused the Django template engine. The syntax has overlapped with Liquid enough that most marketers don't notice, but filters like default and operators like and/or work the Django way.
Can I personalize a button URL with a profile property?
Yes. Reference the property inside the href: <code>{{ person.unique_url|default:'https://example.com' }}</code>. Klaviyo resolves it at send.
How do I include cart line items in an abandoned cart email?
Use the {% for item in event.extra.line_items %} loop. The event scope is available in flow emails triggered by Shopify or Klaviyo's catalog. Test with a real event payload, not synthetic data.
Does Klaviyo support AMP for email?
No, as of 2026 Klaviyo doesn't support AMPHTML. Stick to standard HTML. Most subscribers wouldn't see AMP anyway since only Gmail renders it.
What happens if a Django filter fails on a missing property?
If you used a default filter, the default ships. If not, the email still sends but with an empty string in that slot, which can leave you with 'Hi ,' instead of 'Hi there'. Always include defaults.
Try it yourself

Design in Draftship. Paste into Klaviyo.