Migrating from Loop.

Moving from Loop to Daima is self-serve: export a CSV from Loop, rename its columns to the ones Daima reads, import, activate. The renaming is the work — Daima matches column names literally, so a Loop export will not import as downloaded. Saved cards carry over, so most of your customers never re-enter anything, and nobody gets back-billed. If you'd rather not do the renaming, [email protected] will do it for you.

Read this before you start: do not uninstall Loop Subscriptions first. Shopify cancels any subscription contract owned by an app 48 hours after that app is uninstalled. Uninstalling to "clean up" starts a countdown you cannot stop, on subscriptions you can no longer manage. Migrate first, cancel the old contracts deliberately in Loop, and uninstall last.

Why a migration is needed at all

Shopify ties every subscription contract to the app that created it. An app can only read and manage its own contracts — there is no permission that grants access to another app's. Shopify does this deliberately, to stop two subscription apps billing the same customer twice.

The practical consequence: while your subscribers live in Loop, Daima cannot see them. Daima does not auto-detect them and cannot read Loop's database. They won't appear in your Daima dashboard, they aren't counted in its analytics or revenue, and those customers will see nothing in Daima's customer portal. Migrating re-creates each contract under Daima so it can manage them.

There is no setup fee and no migration fee for this.

Email us first if any of this describes you, before you export, cancel or uninstall anything: more than 5,000 active subscribers, prepaid subscriptions, bundles or build-your-own boxes, or more than one currency. None of those survive a straight CSV reshape, and they are far cheaper to sort out before you have moved anything than after. [email protected], subject line "Migrating from Loop". Everyone else can carry on down this page — the assisted route stays open at any point.

Payment methods are vaulted against the customer, not the app, so Daima reuses the card already on file and your customers don't re-enter anything. Where there's no usable payment method on the Shopify customer record, the contract still imports and activates — Daima flags it, and billing won't succeed until that customer adds one. In practice that's PayPal and wallet-only subscribers, who you'll need to email and ask to re-subscribe.

Step 1 — Export from Loop

In the Loop admin go to Analytics → Reports and open the Subscriptions report, then use Export. Loop describes that report as a list of subscriptions with customer, shipping, payment, products, discounts and next-order details, so shipping addresses come out in the same file rather than a separate one. It is a standard report export, so you do not need to open a support ticket to get your data out.

Two things about how Loop delivers the file:

  • The CSV is emailed to you rather than downloaded on the spot; Loop says the same download link is also available under Reports → Exports inside the app.
  • It expires. Loop's help centre says exported reports stay available for download for 7 days from the time they are generated, after which the report and its download link are removed automatically. Download it as soon as it arrives and keep your own copy.

Take a second export as well: the Subscribed products report, which Loop describes as a "List of subscriptions with detailed product info like price, quantity, discounts etc displayed row wise". If any of your subscriptions carry more than one product, that is the shape you want, because Daima also expects one row per line item (see Step 2). If you have prepaid subscriptions, take Prepaid credit transactions too — read what doesn't come across first, because prepaid does not survive this migration.

There is no single "Loop CSV format". Loop's Subscriptions report is filtered rather than fixed, so what lands in your file depends on the filters and the saved view you exported from, and Loop does not publish the report's header row anywhere public. That's why this page describes what each Daima column needs instead of printing a Loop-to-Daima mapping table. Open your export, read its actual header row, and match it up yourself.

Export the Subscriptions report unfiltered first, so nothing is missing from the file, and only narrow it down (to Active and Paused, say) once you have seen what it actually contains. It is much easier to delete rows and columns later than to go back for another export.

One more thing worth knowing while you still have access: Loop's own migration documentation is explicit that "Historical data (order history) is not migrated during subscription migrations" and that "Analytic information (total subscription spent etc) is not migrated" — and says this applies to all migrations, whichever direction they run. If you want that history, pull it out of Loop as reports now, while the app is still installed. Take the export at a quiet moment rather than in the middle of a billing run, so the file isn't a snapshot of subscriptions that are actively changing under it.

Step 2 — Reshape the export to Daima's columns

This is the part that takes the time, and it is the part nobody can skip.

Daima's importer matches column headers literally. It does not alias, map or fuzzy-match anything. There is no column-mapping screen and no preview step — you drop a file in and it is read. Headers are case-sensitive and must be exactly the lowercase names below: Handle, HANDLE and Customer_Email all fail to match. Surrounding spaces in a header are trimmed, so  handle  is fine, but nothing else is normalised.

Only one column is genuinely required for the upload to be accepted: handle. Every other misspelled or missing column is silently ignored and falls back to a default. That is the trap. A file with Status instead of status imports without complaint and quietly marks everything ACTIVE.

The columns Daima reads

These 25 names are the complete set. Anything else in your file is ignored, which is fine — you can leave Loop's extra columns in place rather than deleting them.

Identity and schedule

  • handle — required. A unique label per subscription. Daima groups rows by it, uses it as the upsert key, and shows it as the contract ID. Any non-empty string works, and it doesn't matter whose ID it is, as long as it is identical on every row belonging to one subscription. Which ID you pick is a real decision if you have multi-product subscriptions — see contracts with more than one product below before you fill this column in.
  • upcoming_billing_date — the next charge date. Convert it to YYYY-MM-DD. See the date warning below; this one bites hardest.
  • status — uppercased by Daima on import, so Loop's Active and Paused become ACTIVE and PAUSED correctly. Defaults to ACTIVE if blank. Only ACTIVE and PAUSED can be activated; Loop's Cancelled and Expired rows import fine but stay as records.
  • cadence_interval — one of DAY, WEEK, MONTH, YEAR. Defaults to MONTH.
  • cadence_interval_count — the multiplier. Defaults to 1.
  • currency_code — e.g. USD. Defaults to USD, and Daima passes it through exactly as written, so type it uppercase.

If your export carries the interval as a single value — 1 week, every 2 months, or similar — Daima needs it split across two columns: cadence_interval = WEEK, cadence_interval_count = 1.

The importer does not validate this field, so a value like Monthly or 30 days uploads without complaint (uppercased to MONTHLY). It fails later, at activation: Shopify only accepts DAY, WEEK, MONTH or YEAR, so the contract is never created and you get a Contract create returned no draft: … error. Split the interval properly before you import — nothing downstream will fix it for you.

Customer

  • customer_id — the numeric Shopify customer ID. Daima strips non-digits, so a full gid://shopify/Customer/123 also works.
  • customer_email — the fallback when customer_id is missing or doesn't match. Fill it in even when you have the ID: it is shown under the customer's name in the imported list and quoted back in the "Customer not found" error, so it is what lets you identify a failing row.

Supply customer_id wherever you can. Daima tries the ID first and only then searches Shopify by email, taking the first customer that search returns. The customer must already exist in Shopify — the importer never creates customers.

Shipping

  • delivery_address_address1 — required to activate.
  • delivery_address_city — required to activate.
  • delivery_address_country_code — required to activate. A Shopify country code such as US, not a country name. Daima uppercases this one but does not translate it, so United States is sent to Shopify as UNITED STATES and rejected.
  • delivery_address_first_name, delivery_address_last_name — these also become the customer's display name in Daima. There is no customer_first_name column; if you supply one it is ignored and the contract shows the customer as "Unknown".
  • delivery_address_address2, delivery_address_province_code, delivery_address_zip, delivery_address_company, delivery_address_phone — optional. province_code is passed through exactly as typed, so write it the way Shopify expects it.
  • delivery_price — shipping charged per cycle. A plain number: 4.95, not $4.95. Defaults to 0.
  • delivery_method_type — accepted and stored, but not used. Activation always creates a shipping contract to the address above.

Loop's Subscriptions report includes shipping data, but whether it arrives as separate address columns or one combined field depends on your export. If it's combined, you will have to split it into the columns above before importing. Daima has no billing-address columns; the shipping address is the only address it reads.

Line items

  • line_variant_id — the one that matters. The numeric Shopify variant ID. A row only becomes a line item if this is filled in, and a contract with no line items cannot be activated. A full gid://shopify/ProductVariant/… also works.
  • line_quantity — defaults to 1.
  • line_current_price — the per-unit price the customer actually pays. Defaults to 0.00.
  • line_selling_plan_name — optional; passed to Shopify as the selling plan name and used as the row's title in Daima.
  • line_selling_plan_id — accepted and stored, but not used at activation.

You will probably have to add the variant IDs yourself. Daima needs numeric Shopify variant IDs, and there is no lookup step in the importer. Check your export: if there is no variant ID column, you'll need to build one, and there is no quick export for it — Shopify's native product CSV export does not include variant IDs. Three routes, by catalogue size: for a handful of products, open each variant in Shopify admin and take the number at the end of the URL (/products/1234/variants/5678); for a full catalogue, use an export app that exposes IDs (Matrixify and similar); or send us your file and we'll match the IDs for you.

It must be the variant ID, not the product ID. A product ID passes the import without complaint and then fails at activation with Shopify's own rejection message.

Contracts with more than one product

One row per line item, all sharing the same handle. Daima groups them into a single contract.

This is where the choice of handle matters, and it is the easiest expensive mistake to make. A multi-product box usually arrives from an export as one row per product, and those rows carry more than one ID: one that is shared by every line in the subscription, and one that is unique to each product line. Use the ID shared by every line. Do that and a four-product box imports as one contract with four line items, billed once. Use the per-product line-item ID instead and the same box imports as four separate contracts, each of which bills that customer on its own.

Sort your sheet by handle before you import and look at the groups. If a customer you know has one four-product box shows up as four one-line contracts, you have picked the wrong column — fix it and re-upload before you activate anything, because after activation those are four live Shopify contracts and the fix has to happen in Shopify instead.

The first row for a handle supplies every contract-level field — status, cadence, dates, customer, address. Contract-level values on the second and later rows are silently discarded. The first row must also carry its own line columns; it is not a parent row. If row one holds only the contract fields and rows two and three hold the products, you get two line items, not three.

Re-uploading a handle replaces that contract's stored line items wholesale rather than appending, so when you fix a contract, re-upload all of its rows together.

Commas and quotes inside values are safe — as long as they stay quoted. Daima's CSV reader is quote-aware: "123 Main St, Apt 4" is read as one value, and a doubled "" inside a quoted value is read as a single quote character. That is what Excel and Google Sheets write when you save as CSV, so a file saved normally survives.

What does break is a value that contains a comma and has lost its surrounding quotes — almost always the result of hand-editing a row in a text editor. The row splits at that comma, every column after it shifts left by one, and it imports looking plausible and wrong, with no error. If you edit the file outside a spreadsheet, keep every value containing a comma wrapped in double quotes.

Convert the dates, and don't trust day-first formats. Open your export and look at whichever column holds the next order date before you touch anything — subscription exports commonly carry a date and a time together in day-month-year order, with no timezone attached. Daima's importer does not validate dates at all: anything it cannot parse silently becomes tomorrow rather than raising an error, and a day-first date such as 15/03/2026 is exactly that case. Worse, 03/15/2026 is parsed — as US month-first order — so a mixed file can convert some rows and mangle others without ever complaining.

Rewrite every upcoming_billing_date as plain YYYY-MM-DD and drop the time. Do this check in your spreadsheet, not in Daima — the imported list does not display the billing date at all, so a mangled date is invisible until the contract is live in Shopify. Sort the column and look for anything that isn't a date, or that landed in the wrong year.

Spreadsheets damage this file, and some of the damage is permanent. You have to open the export to reshape it, so there's no avoiding that here — but know what Excel and Google Sheets do on the way in and out. Postcodes lose leading zeros (07030 becomes 7030). Long IDs turn into scientific notation (4.72295E+13), which is unrecoverable and, worse, still looks like a number. Spreadsheets also add a hidden apostrophe in front of numeric values; Daima strips a single leading apostrophe automatically now, so that one is handled, but the other two are not.

Before you paste anything in, set the ID, postcode and phone columns to Text. Save as UTF-8 CSV, comma-delimited — a semicolon-delimited file (Excel's default in much of Europe) is rejected outright, and a non-UTF-8 save turns accented names and addresses into mojibake without any warning. Keep the untouched original export as your reference copy.

Strip currency symbols from every price column, or you will bill people nothing. Daima reads line_current_price and delivery_price as plain numbers, and does not validate them. $19.99 is not rejected — it is read as 0, activation succeeds, and Shopify creates a live contract that charges that customer 0.00 every cycle, indefinitely, with no error at any point. 19,99 is read as 19. Use a dot decimal, no currency symbol, no thousands separator — and check the prices on your imported rows before you activate anything.

Empty cells that aren't empty

Exports often write -, n/a or none where there is no value. Daima reads those as literal text rather than as blank, so they land in the contract as data. Find and replace them with genuinely empty cells before importing.

Step 3 — Import into Daima

In the Daima admin go to Contracts and choose Import CSV. The upload limit is 10 MB; split a very large export into batches if you're over it.

Importing changes nothing. Imported contracts are records only: no customer is charged, nothing exists in Shopify, and nothing is sent to anyone. You can import, look at the result, fix your file and import again.

Two things to check on the success message rather than taking it at face value:

  • The count is unique handles, not rows. A 500-row file for 120 multi-product contracts correctly reports 120.
  • A file where every row was skipped still reports success — Successfully imported 0 contract(s). If you see a zero, your handle column is empty, not your file.

The imported list only ever shows 25 rows — the 25 most recently imported. There is no paging through the rest. Activated rows, and rows flagged for a missing payment method, drop out of the list entirely — so each round of activation reveals more of what you uploaded, and finished rows can't be re-inspected there. Bulk activation is not limited to what you can see: it works against every pending row in the database, oldest first, ten per click, so on a large migration most of what you activate was never on screen.

Step 4 — Review, then activate

Read the imported rows first. The list gives you the handle, customer name and email, price, frequency and status — check those. Two things it does not show: the product title (imported rows display the selling plan name, or Variant 47229488988312 if you left line_selling_plan_name blank) and the next billing date (the Created column is the import timestamp, not a billing date). Verify those two in your CSV before you activate, not on screen. Note the Price column sums the per-unit prices and ignores line_quantity.

Activate five contracts before you activate five hundred. Pick a handful, use Activate billing one at a time, and check each one in Shopify itself: the contract exists, the price is what the customer actually pays, the next billing date is right, a payment method is attached. Cancel those five in Loop, then let at least one of them bill on its own schedule before you move anyone else. Your file is uniformly shaped, so a mistake in it repeats in every row — the first five will tell you about it while it is still five customers.

Then activate the rest — one at a time, or in bulk. Bulk activation takes ten contracts per click, working against every pending row in the database, oldest first, rather than only the rows on screen — and it tells you how many are left, so on a large migration you'll click it repeatedly. Rows that failed are not retired: they stay eligible and come round again in that same oldest-first order, so a stubborn failure will keep the remaining count higher than you expect. Read the reason printed under a failed row rather than clicking through it.

Activating creates a real Shopify subscription contract with the same products, prices and schedule, and the customer resumes where they left off. From that moment the customer has two live subscriptions — the new Daima contract and the Loop original — and both will bill until you cancel the Loop one in step 5. Don't activate in bulk unless you can finish step 5 the same day. Once a row is activated it drops out of the imported list, because the real contract now appears in your contracts above it.

If a contract's next billing date is today or in the past, Daima steps it forward in whole cadence increments until it lands in the future. A weekly cadence keeps the day of the week; a daily one just adds days. A monthly cadence keeps the day of the month only for days 1–28: a date on the 29th, 30th or 31st rolls over the short month and then sticks permanently — a 31 January date lands in early March and stays on that new, earlier day. If month-end billing matters to your customers, change those dates to the 28th or earlier in your CSV and re-upload those rows before activating; re-uploading a handle replaces it. Nobody is back-billed for the gap, and no missed cycles are charged.

Where there's no usable payment method on the Shopify customer record, the contract still imports and activates — Daima flags it, and billing won't succeed until that customer adds one. In practice that's PayPal and wallet-only subscribers, who you'll need to email and ask to re-subscribe.

Deal with those subscribers before step 5, not after. Cancelling their Loop subscription leaves them holding a Daima contract that will never charge, and the only thing that reaches the customer is Shopify's payment-failure email, and only if you have that notification switched on (Settings → Notifications → Subscriptions) — otherwise you will see it as churn a cycle later. Work out which of your subscribers pay that way, email them a re-subscribe link before you cancel anything in Loop, and if that list is a large share of your base, leave those subscribers running in Loop and move them last.

Step 5 — The cutover order

This is the step that protects your customers, and the one most easily skipped.

The moment you activate in Daima, each migrated customer has two live subscriptions — the new Daima contract and the original in Loop. If both remain active, they will be charged twice.

  1. Activate the contracts in Daima.
  2. Spot-check a handful. In Daima you can confirm the customer, price, frequency and status. The next billing date and the shipping address are not shown on the Contracts screen — check those on the contract itself in your Shopify admin (Customers, then the customer, then their subscription), on two or three migrated customers, before you cancel anything in Loop.
  3. Go back into Loop and cancel the original subscriptions.
  4. Only then uninstall Loop, if you want to.

Do not use uninstalling as a shortcut for cancelling in Loop. Shopify will cancel Loop's contracts 48 hours after uninstall, but it does so silently, on its own timer — and once the app is gone you cannot pause, fix or extend anything that didn't migrate cleanly. Check your Loop plan terms before you cancel the app itself. Keep your exported CSV, and the reshaped version, until the migration is confirmed.

If you want to move in stages, you can leave both apps installed while you work. They do not fight over the same subscriptions, for the same reason the migration is necessary in the first place: each app can only see the contracts it created.

Troubleshooting

"Missing required columns: handle"
There is no column named exactly handle. Usually a capital H, a stray character in the name, or a semicolon-delimited file — in a semicolon file the whole header row is read as one column name, so this is the error you get. It is not surrounding whitespace: Daima trims that from every header before matching.

"CSV file is empty or has no data rows"
Either the file is headers-only, or it uses carriage-return-only line endings from a legacy export. Re-save it with standard line endings.

"Successfully imported 0 contract(s)"
Not actually a success. Every row was skipped for having a blank handle.

A Cancelled or Expired row has no Activate button
Loop's Cancelled and Expired subscriptions import as records but cannot be turned into live contracts, so Daima shows those rows a Delete button instead of Activate billing — there is no error to read. Delete them or leave them as history. Bulk activation skips them too.

"No line items with a variant_id — re-import with line_variant_id populated"
The line_variant_id column is missing, misspelled, or empty on every row for that handle. Every contract needs at least one row with a variant ID.

"Customer not found in Shopify (…)"
The customer_id or customer_email doesn't match anyone in this store. If the message ends in id null, both columns were empty for that row. Daima does not create customers, so the person has to exist in Shopify first.

"No shipping address in the CSV — include delivery_address_address1, city, and country_code columns"
At least one of address1, city or country code is missing. Note that this message shortens the names: the actual headers are delivery_address_address1, delivery_address_city and delivery_address_country_code.

"Delivery method shipping address zip is invalid"
Almost always a spreadsheet artefact rather than a genuinely bad postcode — typically a stray apostrophe in front of numeric values, added by Excel or Google Sheets. Daima strips a single leading apostrophe automatically now, so retry the activation; if it persists, check whether the postcode lost a leading zero.

"Contract create rejected: …" or "Line add rejected (variant …): …"
The tail of these is Shopify's own message, and it is the useful part. Common causes: a product ID where a variant ID belongs, or a currency the store doesn't support.

"Contract create returned no draft: …"
Something in the row is not a value Shopify recognises at all, so it rejected the whole request before validating anything. Almost always cadence_interval (must be exactly DAY, WEEK, MONTH or YEAR) or delivery_address_country_code (must be a two-letter code such as US, not a country name). The braces at the end of the message name the offending field.

"Customer has no stored payment method — they must add one before billing can succeed"
Where there's no usable payment method on the Shopify customer record, the contract still imports and activates — Daima flags it, and billing won't succeed until that customer adds one. In practice that's PayPal and wallet-only subscribers, who you'll need to email and ask to re-subscribe. Do that before you cancel their Loop subscription.

"Payment method scope not granted — customer must add a payment method before billing can succeed"
A different problem with the same symptom: this one is Daima's permission to read stored payment methods, not the customer's card. Email [email protected] rather than contacting the customer.

Everything imported, but the data is wrong in a way you didn't expect
Check the column alignment on the affected row. A value that contains a comma but lost its surrounding quotes during hand-editing shifts every following column by one and imports without an error. A row that is simply short is harmless by comparison — the missing columns come through empty and fall back to their defaults.

What doesn't come across

Some of this is Daima's limitation and some is Loop's. Both are worth knowing before you commit.

  • Prepaid subscriptions. Daima does not ship prepaid, and the importer cannot represent one: it applies a single cadence to both billing and delivery, whereas a Loop prepaid plan bills on one schedule and delivers on another. Loop tracks the remaining prepaid balance as a credit on the subscription that decreases with each delivery, with its own transaction history and a separate Prepaid credit transactions report — and Daima's importer has no column for any of it. If you have prepaid subscribers, email us before you do anything else.
  • Bundles and build-your-own boxes. Loop represents a bundle as a parent product plus child items tied together by an ID that only exists inside Loop. There is no Shopify equivalent, and importing those rows as they stand gives you either free products or a broken box. Loop also installs a bundle snippet into your theme, which stays there after you uninstall — remove it separately.
  • Discounts. Daima's importer has no discount column. Whatever you put in line_current_price is what the customer pays, so bake the discounted price into that number. Recurring percentage discounts do not carry across as discounts.
  • Selling plans and frequencies. The importer stores line_selling_plan_id but does not use it, and importing a contract does not create a matching selling plan on the Daima side. Rebuild your subscription plans in Daima so new customers get the same choices your migrated ones have.
  • Local pickup and other non-shipping delivery. Activation always creates a shipping contract to the address in the CSV. delivery_method_type is accepted but not used.
  • Loyalty, rewards and streak state. If you used Loop Pro's reward journeys, streaks or mystery rewards, none of that has a column in the importer and none of it comes across. Daima has its own loyalty tiers, but migrated subscribers arrive with no accumulated standing — decide in advance whether you're going to credit them manually or start everyone level.
  • Order history, analytics, LTV and cohorts. None of this migrates, in either direction — Loop says so explicitly about its own migrations. Your Daima analytics start from the migration date. Export whatever history you need out of Loop before you uninstall it.
  • Billing addresses. Loop doesn't migrate them and Daima's importer has no columns for them. Only the shipping address moves.
  • Loop Pro features. Loop's Pro tier includes things Daima doesn't offer: prepaid subscriptions, a dedicated CSM and a shared Slack channel, a multi-language customer portal, and user permission management with an exportable account log. If more than one person touches your subscriptions, or you need to be able to show who changed what and when, check that last one against your own requirements before you move — Daima has no equivalent today. Loop's pricing page lists the full set by tier; read it against Daima's feature list rather than assuming parity.

One practical note on getting your data out: as of September 2026 Loop's pricing page puts Custom reporting exports on Enterprise and the Admin REST API on Pro. Below Pro, the manual, emailed, expiring CSV is your export route — another reason to download it the moment it arrives. Check which plan you're on before you assume you have API access.

On Daima's side, be equally clear about what the importer is not: there is no in-app column mapper, no import preview, and no downloadable template CSV. The import screen points at "documentation for the full list of supported columns" — step 2 above is that list.

Running both apps in parallel

You can install Daima alongside Loop and test it before you commit. The two apps coexist safely: each can only see and bill the contracts it owns, so they cannot fight over the same subscription.

What they can do is bill the same customer twice, if you activate a migrated contract in Daima and leave the Loop original running. Parallel testing is safe with new subscribers on a separate product. It is not safe with migrated ones.

If you'd rather not do the reshaping

Email [email protected] with the subject line "Migrating from Loop" and attach your export. We'll reshape it into the Daima columns and hand it back to you ready to import, or run the import for you. No setup fee, no migration fee.

Worth doing regardless if your store is large or your setup is unusual — prepaid subscriptions, bundles, multi-currency, or anything where an export column doesn't obviously map to one of the columns above. Include:

  • Your Shopify store URL, so we can match customer IDs
  • Approximate subscriber count
  • Whether you want your whole book migrated or a small test batch first
  • Your preferred go-live date
  • Whether you used Loop's prepaid or bundle features

Rough guide to how long the assisted path takes: under 500 active subscribers, usually one business day from receiving the file. Between 500 and 5,000, two to three business days, normally a small test batch followed by the rest. Above 5,000, we'll set up a call and stage it over a week. Doing it yourself removes the queue, but the reshaping still has to happen either way. If your export already carries variant IDs and separate address columns, it is an hour's work. If it carries neither, it is a day's — whoever does it.

After you're live on Daima

Once contracts are Daima-owned, everything else follows: they appear in your dashboard, count toward analytics and revenue, feed churn prediction if you are on Pro, and — the thing your customers will notice — become manageable in the Daima customer portal, where they can skip a delivery, pause, resume, move their next billing date, swap a product or cancel themselves.

That last part is the one thing that is not automatic. The customer portal is a page you add to your Shopify customer accounts from the Shopify admin; it is not switched on by default, and until you add it there is no self-serve page for anybody. Do it before you cancel the Loop originals, so the subscribers who could manage their own deliveries there still can — see the customer portal doc.