- /privacy/ page covering the contact form (Formspree), Umami, GA4 and server logs; linked from the footer - Analytics.astro: GA4 alongside Umami, both limited to the production host so staging and local builds are not counted - Dockerfile ARGs + CI build args from repo Actions variables GA_MEASUREMENT_ID and UMAMI_WEBSITE_ID (non-secret)
This commit is contained in:
1 parent
375ee48ab1
commit
0c2b4a6ac6
7 files changed
+154
-8
No files matched your search
+3
-1
@@ -1,7 +1,9 @@
|
||||
PUBLIC_SITE_URL=https://www.bluecapstrategies.com
|
||||
PUBLIC_CONTACT_FORM_ENDPOINT=
|
||||
|
||||
# Analytics — side-by-side trial (ADR-0005). Leave blank to disable each.
|
||||
# Analytics — leave blank to disable each. Production values come from CI (Dockerfile ARGs).
|
||||
# Google Analytics 4:
|
||||
PUBLIC_GA_MEASUREMENT_ID=
|
||||
# PostHog (Cloud free tier recommended for the trial):
|
||||
PUBLIC_POSTHOG_KEY=
|
||||
PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
||||
|
||||
@@ -98,9 +98,13 @@ jobs:
|
||||
# deploy time. CONTACT_FORM_ENDPOINT is the Formspree URL; set it as a repo Actions
|
||||
# secret. If it is empty the build still succeeds and the contact form degrades to a
|
||||
# mailto draft, so a missing secret is survivable but should be caught in review.
|
||||
# GA_MEASUREMENT_ID / UMAMI_WEBSITE_ID are non-secret repo Actions *variables*
|
||||
# (Settings → Actions → Variables); empty means that tracker is simply left out.
|
||||
docker build \
|
||||
--build-arg PUBLIC_CONTACT_FORM_ENDPOINT="${{ secrets.CONTACT_FORM_ENDPOINT }}" \
|
||||
--build-arg PUBLIC_SITE_URL="https://www.bluecapstrategies.com" \
|
||||
--build-arg PUBLIC_GA_MEASUREMENT_ID="${{ vars.GA_MEASUREMENT_ID }}" \
|
||||
--build-arg PUBLIC_UMAMI_WEBSITE_ID="${{ vars.UMAMI_WEBSITE_ID }}" \
|
||||
-t "$PUSH_IMAGE:${{ steps.tag.outputs.sha }}" -t "$PUSH_IMAGE:latest" .
|
||||
# Registry pushes can time out on a slow blob; docker push is resumable, so retry.
|
||||
push_retry() {
|
||||
|
||||
+7
-1
@@ -12,8 +12,14 @@ WORKDIR /app
|
||||
# .gitea/workflows/ci.yml.
|
||||
ARG PUBLIC_CONTACT_FORM_ENDPOINT=""
|
||||
ARG PUBLIC_SITE_URL="https://www.bluecapstrategies.com"
|
||||
ARG PUBLIC_GA_MEASUREMENT_ID=""
|
||||
ARG PUBLIC_UMAMI_SRC="https://stats.bluecapstrategies.com/script.js"
|
||||
ARG PUBLIC_UMAMI_WEBSITE_ID=""
|
||||
ENV PUBLIC_CONTACT_FORM_ENDPOINT=$PUBLIC_CONTACT_FORM_ENDPOINT \
|
||||
PUBLIC_SITE_URL=$PUBLIC_SITE_URL
|
||||
PUBLIC_SITE_URL=$PUBLIC_SITE_URL \
|
||||
PUBLIC_GA_MEASUREMENT_ID=$PUBLIC_GA_MEASUREMENT_ID \
|
||||
PUBLIC_UMAMI_SRC=$PUBLIC_UMAMI_SRC \
|
||||
PUBLIC_UMAMI_WEBSITE_ID=$PUBLIC_UMAMI_WEBSITE_ID
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
---
|
||||
/**
|
||||
* Side-by-side visitor analytics (ADR-0005): PostHog + Umami, each gated by env vars so this is a
|
||||
* no-op until configured. Set the PUBLIC_* vars at build time to enable either or both.
|
||||
* Side-by-side visitor analytics, each gated by env vars so this is a no-op until configured.
|
||||
* Set the PUBLIC_* vars at build time (Dockerfile ARGs, fed by CI) to enable any of them.
|
||||
* - Umami: PUBLIC_UMAMI_SRC (script URL), PUBLIC_UMAMI_WEBSITE_ID — self-hosted, cookieless
|
||||
* - GA4: PUBLIC_GA_MEASUREMENT_ID (G-XXXXXXXXXX)
|
||||
* - PostHog: PUBLIC_POSTHOG_KEY, PUBLIC_POSTHOG_HOST (default https://us.i.posthog.com)
|
||||
* - Umami: PUBLIC_UMAMI_SRC (script URL), PUBLIC_UMAMI_WEBSITE_ID
|
||||
* Track the same event set in both to compare (see docs/seo-aeo-optimization.md §6b).
|
||||
* Umami and GA4 only fire on the production host, so staging/LAN/local visits are not counted.
|
||||
* Anything enabled here must be disclosed on /privacy/.
|
||||
*/
|
||||
const posthogKey = import.meta.env.PUBLIC_POSTHOG_KEY;
|
||||
const posthogHost = import.meta.env.PUBLIC_POSTHOG_HOST ?? "https://us.i.posthog.com";
|
||||
const umamiSrc = import.meta.env.PUBLIC_UMAMI_SRC;
|
||||
const umamiWebsiteId = import.meta.env.PUBLIC_UMAMI_WEBSITE_ID;
|
||||
const gaId = import.meta.env.PUBLIC_GA_MEASUREMENT_ID;
|
||||
const prodHost = new URL(import.meta.env.PUBLIC_SITE_URL ?? "https://www.bluecapstrategies.com").hostname;
|
||||
---
|
||||
|
||||
{
|
||||
@@ -23,6 +27,23 @@ const umamiWebsiteId = import.meta.env.PUBLIC_UMAMI_WEBSITE_ID;
|
||||
|
||||
{
|
||||
umamiSrc && umamiWebsiteId && (
|
||||
<script is:inline defer src={umamiSrc} data-website-id={umamiWebsiteId} />
|
||||
<script is:inline defer src={umamiSrc} data-website-id={umamiWebsiteId} data-domains={prodHost} />
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
gaId && (
|
||||
<script is:inline define:vars={{ gaId, prodHost }}>
|
||||
if (location.hostname === prodHost) {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.gtag = function () { window.dataLayer.push(arguments); };
|
||||
window.gtag("js", new Date());
|
||||
window.gtag("config", gaId);
|
||||
var s = document.createElement("script");
|
||||
s.async = true;
|
||||
s.src = "https://www.googletagmanager.com/gtag/js?id=" + encodeURIComponent(gaId);
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
</script>
|
||||
)
|
||||
}
|
||||
@@ -28,6 +28,6 @@ import { nav, serviceNav, site } from "@data/site";
|
||||
</section>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>(c) 2026 BlueCap Strategies, LLC. All rights reserved.</p>
|
||||
<p>(c) 2026 BlueCap Strategies, LLC. All rights reserved. · <a href="/privacy/">Privacy Policy</a></p>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||
import { site } from "@data/site";
|
||||
import { pageSchema } from "@utils/schema";
|
||||
|
||||
const description =
|
||||
"How BlueCap Strategies collects, uses, and protects information when you visit this website or contact us.";
|
||||
const effectiveDate = "October 23, 2026";
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="Privacy Policy"
|
||||
description={description}
|
||||
pathname="/privacy/"
|
||||
jsonLd={[pageSchema({ title: "Privacy Policy", description, pathname: "/privacy/" })]}
|
||||
>
|
||||
<section class="insights-shell">
|
||||
<article class="note-card privacy-policy">
|
||||
<p class="eyebrow">Effective {effectiveDate}</p>
|
||||
<h1>Privacy Policy</h1>
|
||||
<p>
|
||||
This policy explains what information BlueCap Strategies, LLC ("BlueCap Strategies," "we,"
|
||||
"us") collects through www.bluecapstrategies.com, how we use it, and the choices you have.
|
||||
</p>
|
||||
|
||||
<h2>Information you give us</h2>
|
||||
<p>
|
||||
When you use our contact form, we collect the details you enter: your name, email address,
|
||||
phone number, organization, and message. The form is delivered to us by Formspree, a
|
||||
form-processing service that receives the submission and forwards it to our inbox. We use
|
||||
this information only to respond to your inquiry and to follow up about the work you asked
|
||||
about. You can also reach us directly by email or phone instead of using the form.
|
||||
</p>
|
||||
|
||||
<h2>Website analytics</h2>
|
||||
<p>We use two analytics tools to understand how the site is used and to improve it.</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Umami</strong>, which we host on our own infrastructure. It does not use cookies,
|
||||
does not track you across other websites, and does not store your IP address. It records
|
||||
aggregate information such as the pages viewed, the referring website, browser and device
|
||||
type, and approximate country.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Google Analytics</strong>, provided by Google LLC. It uses cookies to distinguish
|
||||
visitors and measure visits, and the data it collects is processed by Google under
|
||||
<a href="https://policies.google.com/privacy">Google's Privacy Policy</a>. You can opt out
|
||||
by installing the
|
||||
<a href="https://tools.google.com/dlpage/gaoptout">Google Analytics opt-out browser
|
||||
add-on</a> or by blocking cookies in your browser settings.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Server and security logs</h2>
|
||||
<p>
|
||||
Like most websites, our servers automatically record technical details of each request,
|
||||
such as IP address, browser type, the page requested, and the time of the request. We use
|
||||
these logs only to keep the site secure and running, for example to block abusive traffic,
|
||||
and keep them for a limited time.
|
||||
</p>
|
||||
|
||||
<h2>What we do not do</h2>
|
||||
<ul>
|
||||
<li>We do not sell or rent your personal information.</li>
|
||||
<li>We do not use your information for advertising, and we do not show ads on this site.</li>
|
||||
<li>We do not knowingly collect information from children under 13.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Sharing</h2>
|
||||
<p>
|
||||
We share information only with the service providers named above that help us operate
|
||||
this site, or when required by law.
|
||||
</p>
|
||||
|
||||
<h2>Your choices</h2>
|
||||
<p>
|
||||
You may ask us to tell you what information we hold about you from a contact form
|
||||
submission, or to correct or delete it, by emailing
|
||||
<a href={site.contactEmailHref}>{site.email}</a>.
|
||||
</p>
|
||||
|
||||
<h2>Changes to this policy</h2>
|
||||
<p>
|
||||
If we change how we handle information, we will update this page and its effective date.
|
||||
</p>
|
||||
|
||||
<h2>Contact</h2>
|
||||
<p>
|
||||
Questions about this policy can be sent to <a href={site.contactEmailHref}>{site.email}</a>
|
||||
or by phone at <a href={`tel:${site.phone.replaceAll("-", "")}`}>{site.phone}</a>.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
.privacy-policy {
|
||||
max-width: 52rem;
|
||||
margin-inline: auto;
|
||||
}
|
||||
.privacy-policy h2 {
|
||||
font-size: 1.4rem;
|
||||
margin: 2rem 0 0.5rem;
|
||||
}
|
||||
.privacy-policy li + li {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1149,6 +1149,11 @@ textarea:focus {
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.footer-bottom a {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.insights-shell {
|
||||
padding: 4rem 0;
|
||||
display: grid;
|
||||
|
||||
Reference in new issue
Block a user