Privacy Policy

A lot of companies claim they are "privacy oriented" and aren't. Let me show you that there are genuinely levels to this.

Artisan Studios is built on the idea that your business should stay yours - your domain, your payments, your customer relationships, and your data. We design sites that are fast and human-friendly by default, and we avoid data practices that feel "normal" on the modern web but do not actually serve you or your clients.

What we collect (and what we do not)

Short version: we keep data collection light on purpose.
To keep the site stable and secure, we may store basic request metadata (timestamp, requested path, user-agent) for troubleshooting and abuse prevention.

What we do not do: no retargeting pixels, no ad-network profiling, no fingerprinting, and no "follow you around the internet" behavior.

Ownership-first setup

You keep your domain account.
Whenever possible, your domain is registered in your name and managed in your registrar account. We can help with setup and DNS changes, but you retain ownership and access.

You keep your payment processing account.
Payments are processed through your own provider account (Stripe, Square, etc.). We do not want your customers' payment information, and we do not position ourselves as the middleman for your revenue.

Retention + offboarding

We keep information only as long as it is useful for the work we are doing together (or required for legitimate business records).

If we part ways after a build, you can request an export of the site files you paid for, so you are not locked in.

Questions

For analytics, we default to Plausible (privacy-preserving) instead of Google Analytics whenever possible.

Our Plausible instance is hosted on infrastructure we run, so analytics data is kept within systems we directly control.

If you have privacy questions or want a specific setup (no analytics, privacy-preserving analytics, etc.), tell us -- we will design around it.

Third parties

While we try to keep third-party usage to a minimum, there are circumstances where we use outside services for our own operations or for a client project. For anything we use directly for Artisan Studios, we list it here. For client projects, links to all third-party Terms of Service and privacy policies are included in the onboarding packet we deliver with your site.

If you have privacy questions or want a specific setup (no analytics, privacy-preserving analytics, etc.), tell us - we will design around it.

Contact forms

This is the big one:If you reach out for a consult, we only collect what you type in the form: name, email, optional business/site details, and your message. That's it. Your form submission goes to mail infrastructure we run ourselves.

In plain English, your inquiry goes straight to us. It is not getting routed through ad-tech platforms, it is not being sold, and it is not being used to build a marketing profile.

That form flow has one job: confirm your submission and get your message to a real human who can respond. If you want to verify that, check the backend logic below. (Throw it in chatgpt if you need to, I'll wait)

See the code
func buildOwnerMessage(data FormData) string {
	parts := make([]string, 0, 6)
	parts = append(parts, fmt.Sprintf("Name: %s", strings.TrimSpace(data.Name)))
	parts = append(parts, fmt.Sprintf("Email: %s", strings.TrimSpace(data.Email)))

	if business := strings.TrimSpace(data.Business); business != "" {
		parts = append(parts, fmt.Sprintf("Business/Brand: %s", business))
	}
	if siteURL := strings.TrimSpace(data.SiteURL); siteURL != "" {
		parts = append(parts, fmt.Sprintf("Current Site URL: %s", siteURL))
	}

	parts = append(parts, "")
	parts = append(parts, "Project details:")
	parts = append(parts, strings.TrimSpace(data.ClientMessage))
	return strings.Join(parts, "\n")
}

func contactHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}
	var data FormData
	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
		http.Error(w, "bad request", http.StatusBadRequest)
		return
	}
	if strings.TrimSpace(data.Name) == "" || strings.TrimSpace(data.Email) == "" {
		http.Error(w, "name and email are required", http.StatusBadRequest)
		return
	}

	if data.OwnerMessage != "" {
		ownerMessageReader := quotedprintable.NewReader(bytes.NewReader([]byte(data.OwnerMessage)))
		decodedOwnerMessage, err := io.ReadAll(ownerMessageReader)
		if err == nil {
			data.OwnerMessage = string(decodedOwnerMessage)
		}
	}

	if strings.TrimSpace(data.ClientMessage) == "" {
		data.ClientMessage = "No project details were provided."
	}

	if strings.TrimSpace(data.OwnerMessage) == "" {
		data.OwnerMessage = buildOwnerMessage(data)
	}

	ownerDestination := strings.TrimSpace(os.Getenv("CONTACT_OWNER_EMAIL"))
	if ownerDestination == "" {
		ownerDestination = "[email protected]"
	}

	// Email to the user who submitted the form
	if data.Email != "" {
		sendMail(EmailPayload{
			Destination: data.Email,
			Subject:     "Artisan Studios: We received your consult request",
			Body:        buildClientEmail(data),
		})
	}

	// Email to the business owner
	sendMail(EmailPayload{
		Destination: ownerDestination,
		Subject:     fmt.Sprintf("Artisan Studios: New consult request from %s", data.Name),
		Body:        buildOwnerEmail(data),
	})

	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(`{"status":"ok"}`))
}