Privacy Policy
LabelCraft - barcode labels for Shopify that print at exactly the size you set.
Last updated: October 25, 2026
LabelCraft is a Shopify app that prints barcode labels for your products. This policy explains what data the app handles when you install it on your Shopify store, why, and how to get it deleted. A later section covers the public website at labelcraft.tech, which you can read without installing anything. LabelCraft is operated by RidgyDidge SAS, a French company in formation (registered office: 36 avenue Jean Jaurès, 69370 Saint-Didier-au-Mont-d'Or, France), represented by its president, Clement Foltzer, acting in its name and on its behalf until its registration. Until RidgyDidge SAS is registered and takes LabelCraft over, the controller of the personal data this policy describes is Clement Foltzer; this policy will then name the company. The data we keep for your store about your customers and your staff (their order data, and a staff member’s Shopify user ID for the admin language) is the exception: for it, your store is the controller and we handle it on its behalf. You can reach us at support@labelcraft.tech.
Data we store
When you install LabelCraft, we store:
Store information. Your shop’s .myshopify.com domain, subscription plan, monthly label usage count, and app settings (default quantities, GS1 prefix, your declared printer brand and model, and any printer calibration offsets). Since 4 September 2026 we also keep the store owner’s email address, which Shopify uses to contact the owner, read from Shopify when we refresh your store name (about once a month). We write to it, as the owner’s address: one welcome message the day you install; the Tuesday news, once that welcome has announced it, at the address the welcome went to; and, if you have left no address in the app, every other email described under Where data lives: the help email, the one question we ask when you cancel your paid plan, the messages about setting up and about labels that stop coming out, the one question about what you think of the app, and the weekly note on barcode problems in your catalogue. The weekly note goes there too when the box you ticked beside your address does not cover it. Every message carries a one-click unsubscribe, and the address goes with everything else when you uninstall, unless you asked us to stop writing to it: that address then stays on our opt-out list so we can honour it, as the retention section says. Removing the address you left in the app is narrower than unsubscribing: it leaves the owner’s address untouched, and every one of those emails then goes there, and the Tuesday news to the address your welcome went to, if that welcome announced it. The unsubscribe page each of these emails links to can stop all of them, at the address it reached as well as at your store’s other addresses.
Printer connection and station settings. If you connect a printer through PrintNode, we store the PrintNode API key you paste, the printer you pick, and its name, so the app can send jobs to it. That key is used server-side only to talk to PrintNode and is never sent back to your browser. If you set up per-location print stations, we also store, for each Shopify location, the label template and the copies rule that station last used. Both live in the same app settings record as your store information above.
Product data snapshots. Label templates you create and your print job history, which includes the product details printed on labels (titles, variants, SKUs, prices, barcodes). Product data is read from Shopify’s API only to render your labels. The product photos printed on a label, or shown in its preview, are read from Shopify’s image servers at that moment and kept on our server for up to 24 hours from their download, so that a reprint within that time does not download them again; they are then deleted within the hour.
Staff account details. The app reaches your store with an access key Shopify issues to the store, not to a person. Shopify’s sign-in gives us no staff member’s name and no email address (the address listed under “Store information” is read separately, through Shopify’s API). Each screen of the app does carry the Shopify user ID of the staff member using it. That ID is a number with no name or email address, and we use it only for the admin language described in the next paragraph.
Your chosen admin language. Shopify tells us which language your admin is set to only on the first screen you open, so to keep the app in that language as you move around it we store the language together with the Shopify user ID of the staff member it belongs to. That ID, which Shopify puts in the login session, is a number with no name or email address. We keep only one at a time per store, never a list of who works there.
Feedback you write to us. The notes you type into the app’s feedback box are kept with your store, read by us, published nowhere, and deleted with everything else when you uninstall. Under that box you can add an address for us to reply to and tick a box beside it. If you do, two things happen: we keep that address on that one note, and we also send that note and that address to ourselves by email, through Resend, so we can answer you. That email then sits in our support mailbox like any message we receive, and uninstalling deletes your note from the app but does not erase an email we have already been sent. The address receives nothing but our answer, it joins no mailing list, and it is never used to contact you about anything else. When we write back inside the app, our reply is kept with your note and deleted with it, and the first time you open your feedback page after that we record that the reply was shown to you, so we know it arrived and can stop flagging it.
Data we do NOT collect
LabelCraft never asks for your customers’ identity and keeps none of it: no customer name, email, phone number, address, or payment information. If a customer data request carries any, we drop it (see GDPR). From orders and returns, the app reads only the product lines, the number, the date, the ID Shopify gives them and, for a return, its status, and only if you give it access. Of those, it keeps, in your print-job history and on your store’s behalf, only the printed product lines, the order or return number, and the ID Shopify gives the order (see Order and return access).
Order and return access
Two features - printing labels straight from an order, and relabeling a return - need Shopify’s read_orders and read_returns permissions. These are optional: the base install asks only for your products and inventory. You grant order or return access in-context, only when you open those pages, and you can revoke each permission from the page that uses it: order access on “Order labels”, return access on “Returns to label”. Relabeling a return needs BOTH, because in Shopify a return belongs to an order, so “Returns to label” asks for both and “Order labels” is where the order permission is turned off again.
When granted, we read only the label fields. From each order or return line we read the product and variant details needed to print a label - title, variant, SKU, barcode, price, compare-at price, vendor, and weight - plus the quantity (and, for a return, the restocked quantity and the return's status) and the order or return number and date.
We never read customer identity. No customer name, email, phone number, or shipping or billing address is ever requested, read, or stored. Shopify’s install screen names a broad order data category, but LabelCraft selects only the product lines inside an order - never the shopper. See Data we do NOT collect above.
Read live, not stockpiled. Order and return data is read at the moment you print; for a print job made before we kept the order’s ID, Shopify is asked, by the order number already saved there, for that order’s ID and creation date, and only the ID is kept. Nothing from it is kept except the product details and the order or return number saved in your print-job history, so you can find and reprint the same label (see Data we store). Beside that number, the ID Shopify gives the order is kept too, for the reason given under GDPR. The order or return number and that ID stay on a print job for 90 days: once the job is more than 90 days old, a pass that runs every day erases both from it, and the job stays in your print-job history with its product details, so it can still be reprinted. While a customer data request to your store is waiting for our answer, that pass leaves your store’s print jobs as they are, so that the answer can still list them, and it resumes once we have answered; a customer erasure request still removes the order numbers it names. Backup copies of our database keep the number until they expire, at most 90 days after it was erased (see Where data lives).
Hosted in the EU, erased on uninstall. These reads run on our EU servers (see Where data lives) and, like all of your data, are purged when you uninstall (see Data retention and deletion).
How we use data
To provide the service: rendering label PDFs, remembering your templates and settings, enforcing plan quotas, and responding to support requests. Beyond that, and only as the sections below describe, to find where setup and printing break, to understand why a store leaves, to see how stores use the app and what it earns, to decide whom to write to, and to put the app back after a failure. We do not sell data, share it with third parties for marketing, or use it for advertising.
Usage measurement inside the app
Some stores install LabelCraft and never print a label. From outside the app we cannot tell whether they could not find a button, could not connect a printer, or opened it once and closed the tab. So the app records which of its own screens you open, inside the Shopify admin only; what PostHog’s script adds to that, and keeps in your browser, is described below.
What is sent. What we put in them: the name of the screen you opened, your plan, and a pseudonym for your store. Nothing else. No product titles, no SKUs, no prices, no barcodes, no label content, no order or customer data, and no staff name or email address. PostHog’s own script adds to both a technical description of your browser and identifiers of its own, described below.
Your domain does not leave. The pseudonym is the same stable one-way hash of your .myshopify.com domain that the churn record described below uses. It is a pseudonym rather than anonymisation, and this says so instead of pretending otherwise.
How that stays true. The tool we use, PostHog, can be configured to capture every click and every string on a page by itself, and to record the session as video. Both are switched off. Two events leave: the screen view we named by hand, and the one PostHog sends when the app tells it which pseudonym that screen view belongs to, which carries that pseudonym and your plan. On both, PostHog’s script stamps its own technical properties, which we do not remove: the browser and its version, the full line your browser describes itself with (its user agent), the operating system and its version, the device type and, on a phone or tablet, its family (iPhone, Android) and, when the browser gives it, its exact model, the name and version of the app whose built-in browser you use, if you do (Instagram, Facebook, LinkedIn, the Google app and others), the size of your screen and of the window, the language your browser is set to, your time zone, the name of our site, the date and time, the version, settings and counters of PostHog’s own library, and the key of our PostHog project. It also stamps identifiers it creates itself: one for your browser, one for the visit, one for the browser tab and two for each event. Most of them begin with the moment they were created, to the millisecond: the one for your browser carries the date and time of your first visit. The address of the page is cut out of them before they leave, but the connection itself still shows PostHog’s servers the internet address your browser comes from, and we do not switch off the location PostHog derives from it and keeps with each event: the country, the region, the city, the postal code and approximate coordinates. That internet address itself is not kept with the events. Text that happens to be on your screen is never read, and your screen is never filmed.
What stays in your browser. To link the screens of one visit, and the visits of one browser, PostHog’s script keeps the identifiers of your browser and of the visit in your browser’s local storage, under the name ph_<project key>_posthog, with no expiry date, and the tab’s in that tab’s own storage, which the browser empties when the tab closes. Beside them it keeps your store’s pseudonym and your plan, the model of your phone or tablet once it has read it, the address of the first app page it saw and of the page the current visit began on, the page you came from, and a few times, settings and counters of its own. Those addresses are kept as they are, everything after the question mark included, up to about a thousand characters, and whole for the page you came from in the tab’s own storage: they can name your store’s .myshopify.com domain and the language of your admin, hold what you asked to see on that screen, such as the products you had selected in the Shopify admin, the words you typed in one of the app’s search boxes (a product title or a SKU, for example) or a barcode, and carry the session token Shopify gives that page, which holds the Shopify identifier of the staff account that opened it. The token expires within a minute; the copy kept here does not. PostHog does not receive them: the events leave without them. The script also writes a cookie of the same name, set for a year, a year that starts again at each screen, with part of the same record: the identifiers, your store’s pseudonym, the first address, the page you came from and two settings of its own. Inside the Shopify admin, where the app runs in a frame of another site, browsers refuse it; where the app opens as a page of its own, the browser keeps it and sends it with each request to labelcraft.tech and its subdomains, and our servers neither read nor record it. Clearing this site’s data in your browser with LabelCraft closed removes all of it, and your next visit starts with new identifiers; while the app is open, the script writes the identifiers back, with your store’s pseudonym, the addresses, the model of your phone or tablet and its settings, as soon as you open another of its screens, or by itself about half an hour after the last one.
PostHog processes these events on servers in the European Union, the same region as ours. We use them to find where setup breaks. They are not used for advertising and are not shared with anyone, apart from the last screen seen per store, which our code repository keeps (see Where data lives).
The legal basis is our legitimate interest in making the app usable by the people who install it. Because these events are stored under the pseudonym and not under your domain, the automatic purge described below does not reach them. Email support@labelcraft.tech and we will delete them, or keep your store out of this measurement entirely.
This is not Google Analytics. Google Analytics still never runs inside the Shopify admin or during login, exactly as described under The labelcraft.tech website. One measures the public site, the other measures the app, and neither loads where the other runs.
Where data lives
Our servers and database are hosted on Fly.io in Paris, France (European Union). All traffic between your browser, Shopify, and LabelCraft is encrypted with TLS.
Eleven outbound exceptions, one of them only if you set it up. If you connect a printer through PrintNode, the finished label is sent to PrintNode’s service so it can reach your printer. That means the label’s own content - whatever your template prints, such as titles, SKUs, prices, and barcodes - leaves our EU servers for PrintNode, outside the EU, for as long as it takes them to deliver the job. Nothing is sent there unless you have saved a PrintNode key and chosen a printer, and disconnecting PrintNode in Settings stops it.
Email goes out through Resend. Six kinds of email go through Resend, our email provider (its servers, not ours): the welcome message the app sends on install day; the help email we may send, for one of four reasons (warnings on your prints, a trial about to end, printing on one day only, or no print for a while), to the address you leave in the app or, if there is none, to the store owner’s address; the one question we ask when you cancel your paid plan, to the same address as the help email; the other messages to the address you leave in the app, each of them named by the box you tick beside it (setting up, labels that stop coming out, a weekly note on barcode problems found in your catalogue when there are any, the Tuesday news, and one question about what you think of the app), or, if you have left none, all of them except the Tuesday news to the store owner’s address, the weekly note also when the box you ticked does not cover it; the few messages we send to a contact address a store publishes, when we have neither address; and, when you tick the reply box under the feedback form, the copy of your note that we send to ourselves so we can answer you. Resend receives the address and the message, keeps its delivery log, and holds the addresses that unsubscribe, bounce or complain so that we never write to them again; that list is checked, together with our own, before every message to you. The feedback copy is the one that goes the other way, to our own support mailbox, so no opt-out list applies to it. When Resend is unavailable, all of these messages except the welcome and the feedback copy may go out instead through the mail server of our own mailbox, Namecheap Private Email; those are then checked against our own list only.
The Tuesday news, and how to stop it. A short email on Tuesdays tells you what changed in LabelCraft, and only in weeks when something did. It goes to the address you leave in the app when you tick the box that names it, or to the store owner's address Shopify gives us once your welcome email has announced it, with a link that stops it before the first one. It goes out the same way as the messages above and is checked against the same lists. Its own link stops that email alone; everything else we send you stays as it is. A store whose welcome did not announce it, and that has not ticked that box, never receives it.
Error reports go to Sentry. When a screen of the app breaks, the app sends the error to Sentry, our error-tracking provider (its servers, not ours), so that we learn about the fault instead of waiting for you to report it. Sentry receives the error message, the technical trace of where the code stopped, and the address of the screen with everything after the question mark cut off. What else is attached as a label depends on where the fault happened. In your browser: your .myshopify.com domain, your plan, and the two headers a browser attaches by itself, which are the browser and system you run and the address of the page you came from, that one cut at the question mark as well. That report goes from your browser straight to Sentry’s servers, so the connection itself shows them the internet address your browser comes from. On our servers: the address of the screen, and on some of them a reference number that ties the report to our own server log. A report about reading your subscription from Shopify also carries a ten-character code computed from your store’s domain, which names your store only once set beside our own list of domains, and the names and types of the fields Shopify answered, never their values. Since 15 September 2026 no report carries the Shopify user ID of the staff member who hit the fault, the cookies, any other request header, or the content of whatever was being sent when it broke: all of that is cut before the report leaves. No product title, SKU, price, barcode or label content is attached. Sentry keeps these reports in its European region, on servers in Frankfurt, Germany, and we accepted its data processing terms on 15 September 2026.
The live chat goes through Crisp. When the app shows a chat button, the chat window inside the Shopify admin is run by Crisp, our chat provider (its servers, not ours). The chat bubble on the pages of labelcraft.tech is Crisp’s too, and what it sees there is described under The labelcraft.tech website. In the admin, Crisp’s script loads on the app’s screens, so the connection shows Crisp the internet address your browser comes from, and the script can read, like any script on a page, the browser and system you run and the address of the screen you are on. Before it loads, the app cuts from that address the sign-in details Shopify puts in it, the Shopify user ID of the staff member included. The rest of that address stays as it is, so it can hold what you asked to see on that screen, such as the words you typed in one of the app’s search boxes (a product title or a SKU, for example) or a barcode. As soon as the app loads, it hands Crisp your store’s name and your .myshopify.com domain, so the person on duty can see which store is visiting. When you open the chat, the app adds, when it knows them, the code of the last warning one of your prints raised and the name of the template you last printed on. It may also add, next to your store’s domain, a short key signed by our server, so that we can tell a conversation opened from your store’s admin from one that someone else has labelled with your domain. If you answer the two questions the chat asks first, your printer brand and your label size go too. When the app shows you a message from our team in the chat, it notes in Crisp which message it was and its language and, for a message offering help, its reason (warnings on your prints, a trial about to end, printing on one day only, or no print for a while). Crisp then receives what you write, and the address you type if you leave one. To find that conversation again from one screen to the next, its script keeps an identifier for it in your browser. That address serves to answer that conversation and, in the one case described further down, to find your store: it never signs you up for our emails, which only the separate box in the app does, and that box is never ticked in advance. Beyond that address, the app itself sends Crisp no product title, SKU, price, barcode or label content. When one of us marks your support problem as solved, our server reads your conversation in Crisp, its messages included, and your store’s other conversations there, their messages included. To find them, it goes through the list of our conversations in Crisp, with the details each one carries, and keeps nothing from those of other stores or of visitors to the website. Of all that, it uses only your conversation’s channel, whether an email address is attached to it, the signed key, who wrote each message and when, and whether one of our own messages already holds the link to our App Store reviews. It may then write one message into your conversation asking for a review on the Shopify App Store. We keep only the date and the outcome, never what the conversation says. When the app has a message from our team for you (a welcome, a follow-up, a note after your first print, a request for a review after 3 prints in a row without warnings (or 50 labels without warnings over 2 prints), an offer of help or, once on a paid plan, a question about why you chose it), your browser sends our server the identifier of your Crisp conversation; our server checks that the conversation names your store and, when it carries the signed key, that the key is valid, then writes the message into it, so it stays in your history and we can see it. To check, it reads your conversation’s details in Crisp and, before the note after your first print, its latest messages, yours included. Of all that, it uses only the store your conversation names, the signed key, the conversation’s channel, whether an email address is attached to it, and whether one of our own messages already holds the link to our App Store reviews. It never writes the message when an email address is attached to the conversation, or when the check fails or Crisp refuses the message; the app then shows the message only on your screen, as before. We keep only which message it was, the date and the outcome. If you then write to us in the chat, our server adds a private note to the conversation you write in, which only our team sees, listing the messages of ours that the app showed only on your screen, and when. When a member of our team opens your conversation in Crisp, our server shows the state of your store (installation, plan, prints, warnings, messages from our team already shown, our team’s contacts) directly in their browser, without sending it to Crisp. For that, when the chat loads in the app, your browser sends our server the identifier of your Crisp conversation, which our server links to your store; that identifier is kept with your store’s data and deleted with it. Each time a message leaves our side of your conversation in Crisp (a reply from one of us, an automatic message or a note between us), Crisp sends it to our server, its text included; to find your store, our server uses that identifier or, failing it, reads your conversation’s details in Crisp. When those details prove no store and the conversation goes by email, because it began by email or because our reply leaves by email, our server compares the email address the conversation carries with the store owner’s email address and the address left in the app of each installed store, and counts the reply for your store only when yours is the one installed store with that address; it keeps nothing of that address. Of all that, it keeps only, for a reply from one of us and as one of our team’s contacts with your store, the date, which of us replied, the channel and the kind of contact, never what a message says. Our server works that kind out from the state of your store at that moment: installed less than 30 days ago with no label of your own printed yet, a paying store (a trial included) that our checks flag (a template of yours that runs off its label, most of your prints raising a warning, no print for a week or more, a failed print in the last 30 days, a doubt on its billing, or a blocker you told us about), or a question otherwise. Each time you write in your conversation in Crisp, Crisp also sends your message to our server, its text included: that is when our server adds the private note described above, and it never keeps what you write. If you write after our team’s question about why you chose a paid plan, our server also keeps the date of your first message after that question, never what it says, and deletes it with your store’s data.
Store events reach our phone through Telegram. Moments in the life of your store send us a one-line message the day they happen: an install, a plan change, an uninstall, a thumbs-down on the satisfaction question, a data request, and a note left in the feedback box. That list names the common ones rather than all of them: anything that needs our attention the same day can send a line. Those lines go out through Telegram (its servers, not ours). A line names your store only by an eight-character code computed from its domain, the next morning’s summary included. The exception is the message sent the day of an install, a move to a paid plan or between paid plans, the end of a subscription, a frozen payment, an uninstall or a server error on one of your pages or API calls: it carries your store’s name as it reads in Shopify, unless that name looks like an address or a number. None carries your store’s domain. Depending on the event, a line also gives your store’s plan, how many labels it has printed, how many orders a data request covers, or which page of the app had an error. What never travels is the text you typed: a note sends the fact that one arrived and that code, while the note itself stays in the app and reaches us by email. No product, customer or label content is ever in one.
A backup copy of the database goes to GitHub every night. Once a night our whole database is copied onto a machine GitHub runs, checked there, encrypted there, and stored with GitHub, where it stays 90 days and is then deleted. That copy holds everything: the templates, print history and settings of every store, yours included. So the database passes through GitHub’s hardware unencrypted for as long as the check and the encryption take, and the key that opens the encrypted file is kept as a secret inside the same GitHub account that stores the file, which means GitHub holds the file and the key both. Two other copies reach GitHub outside that backup. One is a page of our internal customer dashboard, with a row per store, which we build by hand when we need it and which GitHub deletes after 30 days. The other is a job that runs every morning and commits its results to a branch of our code as a batch of files. Those files are a census of every store we have, flagged or not: a row per store with how many print jobs and labels it ran, how many of them hit a warning, when it installed, how far it got in setup, and when it last printed, plus a row for each store that left, with the reason it chose and the day. In that census, and in the two files beside it that follow each store’s warnings and departures, a store is named by a code computed from its domain with a secret key the branch does not hold: the code alone does not lead back to the domain, but its dates and counts, set beside the files on the branch that keep the domain, can still point to the store. Four parts of the census, which follow trials, the card shown at the end of a trial, our founders’ contacts with a store and what paying stores pay and use, still name a store by the first 8 or 12 characters of a hash of its domain made without that key, which anyone can find again by hashing each domain on the branch; and since some of their rows describe a store the way rows elsewhere in the census describe it under its code, they can tie that code to the domain. Until that change the census carried the domain itself, and the two files a shortened hash of it that their own note called correlatable rather than anonymous; the branch’s history keeps those versions. The results of our checks, committed in the same batch, still name, by its domain, each store a check flags, with the counts behind the flag, such as how many of its print jobs hit a warning, because the next morning’s check and a later step of the same run read them store by store; and the sweep of the catalogues, which a night job also commits, names each store it tried to read, with the size of its catalogue, how many of its barcodes are missing, invalid, duplicated or restricted, how many prices look wrong, the flags on its GS1 prefix and, when the store could not be read, why (for instance that Shopify froze it), and, for each print of the last 30 days that came with a warning, the store, the time of the print and, when we replay it, the type of barcode refused, why, and the sizes measured, so that a store’s catalogue can be looked into. The same branch also keeps the subscription payments Shopify reports to us for the app, each with the store’s domain, an identifier, the date, the net amount, its currency, and whether it was billed monthly or yearly, and the credits and adjustments Shopify reports against them, each with the store’s domain, an identifier, the date, the net amount and its currency; the history Shopify keeps of the app’s events, each with the store’s domain, its identifier, its type, its state and its date and, depending on the event, the reason a leaving store chose, the plan with its billing period, trial days, list price and the day a cancelled subscription ends, the amount charged to the store, Shopify’s commission, the net amount and the day it is paid out, or the amount of a credit, each amount with its currency, and Shopify’s identifiers for the charge concerned; a log of every email we send a store, giving the store’s domain, which of our messages it was, the day, whether it went out, and the address cut down to its first letter and its domain, plus, when we found that address on the store’s own website, the page we found it on; the same details for each store that an email we have not yet switched on would have gone to, with, for a help email, its subject; a copy of the unresolved error reports Sentry holds, each with its title, the text of the error cut to 300 characters, and the stores it touched, named by the same code; and the addresses Resend could not deliver to or will no longer write to, cut down the same way. For each new store still installed when our morning pass reads it, it also keeps a short note read from the app and from the store’s own public website: its domain and name, its country, what its website says it sells, its plan, how many labels it printed, whether its welcome went out, whether it cancelled a Pro trial, and whether we found an Instagram account for it. When we look into a print problem a store ran into, the branch also keeps our working files on it: the store’s domain or name, the titles, variants and their Shopify IDs, vendors, SKUs, barcodes, prices and weights of the products concerned, how many of each were printed, and the template it printed with, including the font file it had uploaded. Some of those titles and templates were also copied into the tests of our code; we have since replaced them there with invented titles and with templates of our own, which leaves them only in our code’s history and in its pull requests on GitHub. Beyond the files named above, that branch and our code repository itself, meaning its code, the data files it carries, its tests and comments, and the working notes we keep beside them (our backlog, plans, reports, audits, notes and our work journal), name some stores by their domain or by a shortened hash of it, sometimes with their name, website, country and what they sell, next to what we knew or had measured about them at the time: how they found us, one of our ads included; when they installed, started or ended a trial, changed plan, closed or reopened their store, or left, and the reason they picked; their plan, billing events and payments; their Shopify plan, the age of their store, the size of their catalogue, how many locations it has and how often it receives stock in Shopify; how many print jobs and labels they ran and which warnings came up; how far they got in the app, down to the last screen they were seen on; their printer and label stock, whether they connected a printer, and which of the app’s offers they were shown and which they took; their answer to our satisfaction question; the health of their barcodes and their GS1 company prefix; what our own checks flagged; the browser and language of an error they ran into; the first name, sometimes the full name, of a person who wrote to us, and what they wrote or reported, at times word for word; which of our emails and review requests reached them, at which address, when, and what came of each or why one was held back; when one of us last contacted them; the review they left on the App Store; and what we decided about contacting them. Those mentions are in the current version of the repository, not only in its history: they stay there until we edit them out, and the history keeps them for as long as the repository exists. A branch keeps what is written to it until we take it out, and the repository’s history keeps every earlier version for as long as the repository exists. The repository belongs to our organisation on GitHub’s Team plan, and we have signed GitHub’s Customer Agreement. A backup is what puts the app back on its feet after a failure, so a copy taken before you uninstall keeps your data until its 90 days run out, and the deletion described below does not reach it. Why we keep all of this, on the basis of our legitimate interest (GDPR, Article 6(1)(f)): the backup, to put the app back after a failure; the census, the dashboard page, the payments and the app’s event history, the email logs, the error copies and the notes on new stores, to see how stores use the app, where printing goes wrong, what the app earns, which emails went out and whom to write to; the working files on a print problem and the mentions in our repository, to fix what a store ran into and keep that fix tested. You can object to it (GDPR, Article 21), as described under GDPR below.
What a store typed as it left, and who reads our code. Until 6 October 2026 the branch described above also kept the words a store may have typed as it left: Shopify shows a store that uninstalls a short survey and passes its answer on to us, the reason picked from its list and, when there is one, the text typed beside it. A few of those words were also quoted in our working notes, in comments in our code and in the description of one of our pull requests. We stopped copying them that day; those already written stay in the history of our repository and in its pull requests on GitHub, sometimes next to the store’s domain, for as long as the repository exists. Our team reads that repository, GitHub hosts it, a server we rent from Hetzner in the European Union keeps a copy of it and of the branch, and the coding assistants we have working in it read it too: Claude, from Anthropic, and Codex, from OpenAI. We collected those words on the basis of our legitimate interest in understanding why a store leaves, so that we could fix the app (GDPR, Article 6(1)(f)). We stopped using them for that on 6 October 2026. On 7 October 2026 we read them once more, only to count them for this notice and to replace their quotes in our current code and notes with our own words; those rewordings stay there, and the words themselves stay only because we do not rewrite that history. You can object to that (GDPR, Article 21), or ask us to take your store’s words out of everything we still use: write to support@labelcraft.tech. That takes them out of what we use, not out of the history of our repository, which we do not rewrite: it is narrower than having them erased (GDPR, Article 17).
Where GitHub, Anthropic and OpenAI keep what they read, and on what terms. GitHub, Inc., in the United States, keeps the repository, the branch, the nightly backup and the other copies described above as our processor, under GitHub’s Data Protection Agreement, which the Customer Agreement we signed brings in: GitHub handles that data on our instructions, apart from the few purposes of its own the agreement lists (such as billing, its legal obligations, abuse and security checks, and aggregated statistics), and may not use it for anything else, model training included. Its transfer to the United States rests on the European Commission’s standard contractual clauses, which that agreement incorporates, and on GitHub’s self-certification under the EU-U.S. Data Privacy Framework (GDPR, Articles 45 and 46). Claude and Codex, on the other hand, read our repository and the branch through our founders’ individual accounts, not under a business contract. Anthropic and OpenAI therefore each handle what their assistant reads, as a controller in its own right, under their own privacy policy rather than on our instructions. Because our founders live in the European Union, the companies they deal with are Anthropic Ireland, Limited and OpenAI Ireland Limited, which send it on to servers in the United States and other countries outside the European Union, relying on the European Commission’s standard contractual clauses (and, for some countries, on an adequacy decision; Anthropic, in some situations, also on the derogations the GDPR allows). For data about people who live outside the European Economic Area, the United Kingdom and Switzerland, Anthropic names its US company, Anthropic, PBC, as controller: that transfer rests on no adequacy decision Anthropic claims and on no agreement of ours. Each may also use what it reads to improve its models, unless the account’s training settings refuse it, and even then when one of us gives feedback on an answer and, at Anthropic, when it flags content for a safety review.
A continuous copy of the database is kept with Tigris. Every change written to our database is copied, about a second later, to Tigris Data, Inc., a company in the United States whose storage service our host Fly.io sells us (its servers, not ours). If the machine that holds our database becomes unreachable, that copy lets us restart the app on another machine without losing the day’s work. It holds everything the database holds: the templates, print history and settings of every store, yours included. A row deleted from our database is gone from the copy within two days. Tigris handles the copy on our instructions, as our processor, under its data processing addendum; the transfer to the United States rests on the European Commission’s standard contractual clauses, which that addendum incorporates (GDPR, Article 46). Why we keep it, on the basis of our legitimate interest (GDPR, Article 6(1)(f)): to put the app back after a failure. You can object to it (GDPR, Article 21), as described under GDPR below.
Data retention and deletion
When you uninstall LabelCraft, Shopify sends us a deletion request and we purge all of your store’s data - templates, print history, settings (including any PrintNode key you saved), and login sessions. We run that purge once Shopify confirms the uninstall to us, which Shopify’s data protection terms put at 48 hours; the confirmation is Shopify’s to send, so it can occasionally reach us later than that.
Five narrow records outlive that purge. So does what has already left for the providers named above: the nightly backup for its 90 days, the continuous copy at Tigris for two days at most, the dashboard page for its 30, the branch until we take it out and its history for as long as our code repository exists (it keeps, among the rest, the log of the emails we sent a store, with the date we sent it our one question about what it thinks of the app, so that a store that reinstalls does not receive that email a second time; it also keeps the payments and the history of the app’s events described above and, for a store that left before 6 October 2026, the words it may have typed as it left), our code repository itself and its history, which mention some stores together with what we knew about them, as described above (in our code, the product titles and templates we had copied there have been replaced with invented titles and templates of our own and remain in its history and in its pull requests, while our working files on the branch still hold them), the error reports, the one-line store events and the chat conversations for as long as those providers keep them, what the coding assistants named above have read, for as long as the companies that run them keep it under their own policies, the delivery log of a message at our email provider, an email you have already sent us, and the usage events under your pseudonym until you ask us to delete them. In your own browser, what PostHog’s script and the chat’s keep there stays until it expires or you clear it, and so do a few settings of the app itself, which say nothing about your store; a print selection you leave without printing stays in the tab’s own storage until the tab closes. Nothing else of your store’s outlives that purge. Three are markers, each one line: if your store started a Pro free trial we keep your .myshopify.com domain with the date the trial was used; if the app opened Pro to your store for 14 days when it was installed, we keep the domain with the date it opened it; and if your store uninstalled while we still had it recorded as installed we keep the domain with the date the install was first announced. They exist to stop one store taking an endless run of free trials by reinstalling, and to stop a returning store being announced as brand new. The fourth is a churn record, written once when a store uninstalls: how long the install lasted, which setup steps it reached, how many templates, saved lists, print jobs and labels there were, and which warning codes came up - and, for each of those codes, how many print jobs hit it on each day, so we can tell whether a fix we shipped actually stopped the problem for the stores it had been failing. It also records which plan the store was on when it left, whether that plan was paid, billed monthly or yearly, and whether the store was still inside its free trial - we keep it to tell a trial that ended from a subscription that was cancelled. And it carries, when you gave them, the two short answers you chose from our own lists: why you were leaving, if you told us while cancelling, and why you had not printed yet, if you answered that question in the app. Only the option you picked travels, never anything you typed in the box beside it - that text stays on your store's record and is deleted with it. It is stored under a shortened one-way hash of your domain rather than the domain itself - a pseudonym, not full anonymisation - and it holds no product, order, customer or staff data and no label content. We keep it to understand why stores leave. The fifth is an opt-out list: if anyone asks us to stop emailing an address, we keep that address so we can honour it. It outlives your store on purpose, because a request to be left alone that we forget is a request we did not honour.
Three counters on our side are not about your store at all, so none of the above reaches them. One is a daily tally of how many people clicked from the public labelcraft.tech pages towards our App Store listing: a date, which button, which campaign, and a number. Another is a daily copy of what our own advertising on the App Store cost us and how many installs it brought, which is Shopify's figure about our spending, not about you. The third measures how fast the app itself loads: for each day we count, in speed ranges, the standard web performance readings (largest paint, input delay and the like) that Shopify's own admin toolkit reports - a date, a metric name, a screen name, a speed range, and a count. None of the three holds a store, a person or a device, so a deletion request finds nothing in any of them to erase. The first is described in full under The labelcraft.tech website.
You can also request deletion or a copy of your data at any time by emailing support@labelcraft.tech.
The labelcraft.tech website
This section is about the public site you are reading, not about the app. Browsing labelcraft.tech installs nothing and creates no account, and the site itself never ties your visit to a Shopify store. The one way a conversation may come to be tied to one is the chat, described at the end of this section.
We run Google Analytics 4 on the public pages to count visits and see which pages lead to an install. It never loads inside the Shopify admin or during login. What it stores on your device depends on where you are, and there are three cases.
In the United States, Canada outside Quebec, Australia and New Zealand it sets one first-party cookie, _ga, holding a random number so that several page views count as one visit. No advertising cookie is set in those four countries, ever, and you are not asked anything.
In Quebec, it stores nothing and nothing is asked: the tag runs without a cookie and Google publishes none of it.
Everywhere else, the European Economic Area, the United Kingdom and Switzerland included, a bar asks before Google writes anything. Refuse it, or ignore it, and Google sets no cookie. Accept and two things start together: the _ga cookie above, and Google’s advertising storage, which lets us see which ads bring installs and can be used to show you our ads on other sites.
Google receives your IP address to work out an approximate country, and does not store it. We never send your name, your email, or anything else that identifies you. To opt out, block or delete the _ga cookie in your browser settings, or install Google’s opt-out add-on. Your answer to the bar is kept in your own browser under lc-consent-v1. To change your answer, use the Cookies button at the bottom of any page: the bar comes back and your new choice replaces the old one. Clearing this site’s data works too. Every page keeps working whatever you choose.
Separately from Google, we count the clicks that leave for our App Store listing. When you click an Install button, your browser sends our own server three things: today’s date, which button you clicked, and which campaign the link carried. Nothing is written to your device and nothing is read from it, no identifier is created, and the message is byte for byte the same whether you accepted the bar, refused it, or never saw it, because nothing in it could tell you apart from the next visitor. All we ever keep is a running total per day and per button. We added it because Google Analytics reports to us in the four countries above and nowhere else, so before it we had no way to know whether our own ads brought anyone at all.
The chat bubble is Crisp’s, and it loads for every visitor. A chat bubble sits in the corner of every page of this site except the unsubscribe and sign-in pages, so that you can write to us from here. It is run by Crisp, the chat provider described under Where data lives. Its script loads as soon as a page opens, for every visitor, before you answer the cookie bar and whatever you answer, because it is how you reach us. The connection shows Crisp the internet address your browser comes from, and the script can read, like any script on a page, the browser and system you run and the address of the page you are on. It sets Crisp’s own cookies on this site, whose names begin with crisp-client, and they keep an identifier of your conversation for about six months, so that a conversation you start finds you again on your next visit. If you write, Crisp receives what you write, and the address you type if you leave one; that address serves to answer you (and, in one case described below, to find your store) and never signs you up for our emails. The site itself sends Crisp nothing about you: no name, no email address, no store. Each time a message is written in your conversation, by you or on our side, Crisp also sends it to our server, its text included, because the chat in our app uses the same Crisp account. Our server only looks for a store tied to the conversation, in its own records or in your conversation’s details in Crisp; while there is none, it keeps nothing. A conversation started here is tied to no store, with two exceptions. If one of us answers you by email, our server compares the address you left with the store owner’s email address and the address left in the app of each installed store; when exactly one installed store carries it, the server counts that reply as one of our team’s contacts with that store (the date, which of us replied, the channel and the kind of contact, never what a message says) and keeps nothing of the address. And if you then open LabelCraft in your Shopify admin in the same browser, the app may find that same conversation and add your store’s name and domain to it, as described under Where data lives. The reverse holds too: a conversation you started in the app may be picked up here, with your store’s name and domain. To remove these cookies, clear this site’s data in your browser.
GDPR
LabelCraft implements Shopify’s mandatory privacy webhooks. We store no customer identity (no name, email, phone number or address): the app never asks Shopify for them, and when a customer data request carries them, we drop them without keeping them. If, on the other hand, you use Order labels or Returns to label, the order or return number stays in your print-job history for 90 days after the print, or longer while a customer data request is waiting for our answer (see Order and return access).
A customer data request is answered from that history. When a shopper asks a store you run for the data we hold about them, Shopify tells us which orders the request covers. We record the request, look those orders up in your print-job history, and undertake to provide you, the store owner, with what we hold about them - the order or return number, the date, and how many labels were printed - or to tell you there are none, within the 30 days Shopify allows. We keep one record of each request we receive, holding the dates it arrived and was answered and at most the IDs Shopify gives the orders it named (none of them once we have found that we hold nothing about those orders), so that it can be shown to have been answered. No shopper name, email address or phone number is stored: the request carries them, and we drop them. The record is erased with the rest of your store’s data (see Data retention and deletion).
A customer erasure request removes those numbers. The order numbers named in the request are erased from your print-job history, and from our record of any earlier request about the same orders. A print job made from an order or a return also keeps, next to the order number, the ID Shopify gives that order (for a return, the order it belongs to), because an erasure request names orders by their ID, not their number: the ID is kept so that the request can find them, and it is erased along with the number. Backup copies keep them until they expire, at most 90 days later (see Where data lives). Shop data erasure is honored automatically as described above. If you are in the EU/EEA you may also contact us to exercise your rights of access, rectification, erasure, restriction of processing and portability, and your right to object to what we keep on the basis of our legitimate interest. You can also lodge a complaint with a data protection supervisory authority, in particular in the EU/EEA country where you live or work or where you think your rights were infringed (GDPR, Article 77).
Changes
If this policy changes materially we will update this page and note the new date at the top. Continued use of the app after a change constitutes acceptance.
Contact
Privacy questions: support@labelcraft.tech