By proceeding, you agree to our{' '}
-
+
Terms of Service
{' '}
and{' '}
-
+
Privacy Policy
.
diff --git a/apps/remix/app/routes/_share+/share.$slug.tsx b/apps/remix/app/routes/_share+/share.$slug.tsx
index 4e8029f73e..17c9431b54 100644
--- a/apps/remix/app/routes/_share+/share.$slug.tsx
+++ b/apps/remix/app/routes/_share+/share.$slug.tsx
@@ -12,15 +12,15 @@ export function meta({ params: { slug } }: Route.MetaArgs) {
}
return [
- { title: 'Documenso - Share' },
- { description: 'I just signed a document in style with Documenso!' },
+ { title: 'Crove Sign - Share' },
+ { description: 'I just signed a document in style with Crove Sign!' },
{
property: 'og:title',
- content: 'Documenso - Join the open source signing revolution',
+ content: 'Crove Sign - Electronic signatures for the Crove OS ecosystem',
},
{
property: 'og:description',
- content: 'I just signed with Documenso!',
+ content: 'I just signed with Crove Sign!',
},
{
property: 'og:type',
@@ -32,7 +32,7 @@ export function meta({ params: { slug } }: Route.MetaArgs) {
},
{
name: 'twitter:site',
- content: '@documenso',
+ content: '@crovedos',
},
{
name: 'twitter:card',
@@ -44,7 +44,7 @@ export function meta({ params: { slug } }: Route.MetaArgs) {
},
{
name: 'twitter:description',
- content: 'I just signed with Documenso!',
+ content: 'I just signed with Crove Sign!',
},
];
}
@@ -69,8 +69,8 @@ export const loader = async ({ request, params: { slug } }: Route.LoaderArgs) =>
return {};
}
- // Is hardcoded because this whole meta is hardcoded anyway for Documenso.
- throw redirect('https://documenso.com');
+ // Non-share visitors (bots excluded above) land on the app home.
+ throw redirect(NEXT_PUBLIC_WEBAPP_URL());
};
export default function SharePage() {
diff --git a/apps/remix/app/routes/_unauthenticated+/privacy.tsx b/apps/remix/app/routes/_unauthenticated+/privacy.tsx
new file mode 100644
index 0000000000..8f7b48110c
--- /dev/null
+++ b/apps/remix/app/routes/_unauthenticated+/privacy.tsx
@@ -0,0 +1,97 @@
+import { Button } from '@documenso/ui/primitives/button';
+import { Trans } from '@lingui/react/macro';
+import { Link } from 'react-router';
+
+// PLACEHOLDER LEGAL TEXT: replace with a privacy policy reviewed for the
+// operating entity before relying on it commercially.
+export default function PrivacyPolicy() {
+ return (
+
+
+
+ Privacy Policy
+
+
+
+
+ Last updated: September 2026. This policy explains what personal data Crove Sign processes, why, and the
+ choices you have.
+
+
+
+
+ 1. Data We Process
+
+
+
+ Account data (name, email, avatar) synced from your identity provider, the documents you upload, signature
+ and audit metadata, and technical logs such as IP address and user agent required to operate the service.
+
+
+
+
+ 2. Why We Process It
+
+
+
+ To provide the signing service, keep documents and audit trails verifiable, send you transactional emails
+ about your documents, prevent abuse, and comply with legal obligations.
+
+
+
+
+ 3. Document Confidentiality
+
+
+
+ Your documents are processed only to deliver the service. We do not use your document contents for
+ advertising or train models on them.
+
+
+
+
+ 4. Data Sharing
+
+
+
+ We share data only with the infrastructure providers that operate the Crove OS ecosystem, with recipients
+ and senders involved in a signing workflow, and where required by law.
+
+
+
+
+ 5. Retention
+
+
+
+ Documents and audit records are retained while your account is active and as required for the integrity of
+ completed signings. You can request deletion of your account and associated data.
+
+
+
+
+ 6. Your Rights
+
+
+
+ You can access, correct, export, or delete your personal data through your account settings or by contacting
+ support through the Crove OS ecosystem channels.
+
+
+
+
+ 7. Contact
+
+
+ Privacy questions can be sent through the support channels of the Crove OS ecosystem.
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/remix/app/routes/_unauthenticated+/terms.tsx b/apps/remix/app/routes/_unauthenticated+/terms.tsx
new file mode 100644
index 0000000000..e82fca8ef4
--- /dev/null
+++ b/apps/remix/app/routes/_unauthenticated+/terms.tsx
@@ -0,0 +1,119 @@
+import { Button } from '@documenso/ui/primitives/button';
+import { Trans } from '@lingui/react/macro';
+import { Link } from 'react-router';
+
+// PLACEHOLDER LEGAL TEXT: replace with terms reviewed for the operating
+// entity before relying on them commercially.
+export default function TermsOfService() {
+ return (
+
+
+
+ Terms of Service
+
+
+
+
+ Last updated: September 2026. These terms govern your use of Crove Sign, the electronic signature service
+ operated as part of the Crove OS ecosystem.
+
+
+
+
+ 1. Acceptance of Terms
+
+
+
+ By creating an account or using Crove Sign you agree to these Terms of Service. If you use the service on
+ behalf of an organisation, you confirm that you are authorised to bind that organisation.
+
+
+
+
+ 2. The Service
+
+
+
+ Crove Sign lets you prepare, send, sign, and manage documents electronically, including advanced electronic
+ signatures and optional blockchain-sealed attestation records. The service is provided through the web
+ application and its associated APIs.
+
+
+
+
+ 3. Your Account
+
+
+
+ You are responsible for safeguarding the credentials to your identity provider account, for the accuracy of
+ the information you provide, and for all activity carried out under your account.
+
+
+
+
+ 4. Your Documents and Content
+
+
+
+ You retain all rights to the documents you upload and the signatures you apply. You grant us only the
+ limited rights needed to store, process, and deliver those documents as part of providing the service.
+
+
+
+
+ 5. Legal Effect of Electronic Signatures
+
+
+
+ Electronic signatures carry legal effect under applicable law when the signatory intends to sign. You are
+ responsible for ensuring that your use of electronic signatures satisfies the legal requirements of your
+ jurisdiction and document type.
+
+
+
+
+ 6. Acceptable Use
+
+
+
+ You may not use the service to send unwanted signing requests, to mislead signers about what they are
+ signing, or for any unlawful purpose.
+
+
+
+
+ 7. Availability and Changes
+
+
+
+ We may modify or discontinue features, and may update these terms. Material changes will be communicated
+ through the service before taking effect.
+
+
+
+
+ 8. Limitation of Liability
+
+
+
+ To the maximum extent permitted by law, the service is provided "as is" and we are not liable for indirect
+ or consequential damages arising from your use of the service.
+
+
+
+
+ 9. Contact
+
+
+ Questions about these terms can be sent through the support channels of the Crove OS ecosystem.
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/remix/public/android-chrome-192x192.png b/apps/remix/public/android-chrome-192x192.png
index 7613afd598..ad35dbc634 100644
Binary files a/apps/remix/public/android-chrome-192x192.png and b/apps/remix/public/android-chrome-192x192.png differ
diff --git a/apps/remix/public/android-chrome-512x512.png b/apps/remix/public/android-chrome-512x512.png
index 9d6675a6a4..96d8f5f7e6 100644
Binary files a/apps/remix/public/android-chrome-512x512.png and b/apps/remix/public/android-chrome-512x512.png differ
diff --git a/apps/remix/public/apple-touch-icon.png b/apps/remix/public/apple-touch-icon.png
index 22b756a89d..e3b94a7f42 100644
Binary files a/apps/remix/public/apple-touch-icon.png and b/apps/remix/public/apple-touch-icon.png differ
diff --git a/apps/remix/public/favicon-16x16.png b/apps/remix/public/favicon-16x16.png
index ddb28ae723..2ff3438a54 100644
Binary files a/apps/remix/public/favicon-16x16.png and b/apps/remix/public/favicon-16x16.png differ
diff --git a/apps/remix/public/favicon-32x32.png b/apps/remix/public/favicon-32x32.png
index 210dcb4d10..0734c47db8 100644
Binary files a/apps/remix/public/favicon-32x32.png and b/apps/remix/public/favicon-32x32.png differ
diff --git a/apps/remix/public/favicon.ico b/apps/remix/public/favicon.ico
index b295574836..6d60870ab5 100644
Binary files a/apps/remix/public/favicon.ico and b/apps/remix/public/favicon.ico differ
diff --git a/apps/remix/public/opengraph-image.jpg b/apps/remix/public/opengraph-image.jpg
index 7be4300005..b4e2f668e9 100644
Binary files a/apps/remix/public/opengraph-image.jpg and b/apps/remix/public/opengraph-image.jpg differ
diff --git a/apps/remix/public/static/logo.png b/apps/remix/public/static/logo.png
index 4813aaaef0..7f598d08d5 100644
Binary files a/apps/remix/public/static/logo.png and b/apps/remix/public/static/logo.png differ
diff --git a/apps/remix/public/static/og-share-frame.png b/apps/remix/public/static/og-share-frame.png
new file mode 100644
index 0000000000..e92f505532
Binary files /dev/null and b/apps/remix/public/static/og-share-frame.png differ
diff --git a/apps/remix/public/static/og-share-frame2.png b/apps/remix/public/static/og-share-frame2.png
index b9a65657da..4a2ebd6708 100644
Binary files a/apps/remix/public/static/og-share-frame2.png and b/apps/remix/public/static/og-share-frame2.png differ
diff --git a/packages/assets/logo_icon.png b/packages/assets/logo_icon.png
index cb4765fcf1..b9167e38ee 100644
Binary files a/packages/assets/logo_icon.png and b/packages/assets/logo_icon.png differ
diff --git a/packages/assets/static/logo.png b/packages/assets/static/logo.png
index 4813aaaef0..7f598d08d5 100644
Binary files a/packages/assets/static/logo.png and b/packages/assets/static/logo.png differ
diff --git a/packages/assets/static/og-share-frame.png b/packages/assets/static/og-share-frame.png
index 72bf7dd963..e92f505532 100644
Binary files a/packages/assets/static/og-share-frame.png and b/packages/assets/static/og-share-frame.png differ
diff --git a/packages/assets/static/og-share-frame2.png b/packages/assets/static/og-share-frame2.png
index b9a65657da..4a2ebd6708 100644
Binary files a/packages/assets/static/og-share-frame2.png and b/packages/assets/static/og-share-frame2.png differ
diff --git a/packages/email/template-components/template-branding-logo.tsx b/packages/email/template-components/template-branding-logo.tsx
index 6b560aed29..f3d2bf8400 100644
--- a/packages/email/template-components/template-branding-logo.tsx
+++ b/packages/email/template-components/template-branding-logo.tsx
@@ -23,7 +23,7 @@ export const TemplateBrandingLogo = ({ assetBaseUrl, className = 'mb-4 h-6' }: T
if (!hasCustomBrandingLogo) {
const documensoLogoUrl = getEmailAssetUrl(assetBaseUrl, 'static/logo.png');
- return ;
+ return ;
}
const brandingLogo = ;
diff --git a/packages/email/template-components/template-footer.tsx b/packages/email/template-components/template-footer.tsx
index ed82efb783..4ca0f94c67 100644
--- a/packages/email/template-components/template-footer.tsx
+++ b/packages/email/template-components/template-footer.tsx
@@ -1,3 +1,4 @@
+import { APP_COMPANY_DETAILS, NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { Trans } from '@lingui/react/macro';
import { Fragment } from 'react';
@@ -33,7 +34,7 @@ export const TemplateFooter = ({ isDocument = true, reportUrl }: TemplateFooterP
This document was sent using{' '}
-
+
Documenso
.
@@ -64,9 +65,16 @@ export const TemplateFooter = ({ isDocument = true, reportUrl }: TemplateFooterP
{!branding.brandingEnabled && (
- Documenso, Inc.
-
- 2261 Market Street, #5211, San Francisco, CA 94114, USA
+ {APP_COMPANY_DETAILS()
+ .split('\n')
+ .map((line, idx) => {
+ return (
+
+ {idx > 0 && }
+ {line}
+
+ );
+ })}
)}
diff --git a/packages/email/templates/admin-user-created.tsx b/packages/email/templates/admin-user-created.tsx
index 000b4d3cbd..45f434532a 100644
--- a/packages/email/templates/admin-user-created.tsx
+++ b/packages/email/templates/admin-user-created.tsx
@@ -24,7 +24,7 @@ export const AdminUserCreatedTemplate = ({
-
+
diff --git a/packages/lib/constants/app.ts b/packages/lib/constants/app.ts
index 8ab113b738..7a47b2021d 100644
--- a/packages/lib/constants/app.ts
+++ b/packages/lib/constants/app.ts
@@ -184,3 +184,10 @@ export const CSC_INSTANCE_SIGNATURE_LEVEL = (): TSignatureLevel => {
};
export const DOCUMENSO_CLOUD_ENTERPRISE_CTA_URL = 'https://documen.so/enterprise-cta';
+
+/**
+ * Company identity rendered in the email footer when an organisation has no
+ * custom branding. Override per deployment (legal address, site, etc.) via
+ * the NEXT_PRIVATE_BRANDING_COMPANY_DETAILS env (newline-separated lines).
+ */
+export const APP_COMPANY_DETAILS = () => env('NEXT_PRIVATE_BRANDING_COMPANY_DETAILS') || 'Crove\nhttps://crove.com';
diff --git a/scripts/patch-crove-branding.mjs b/scripts/patch-crove-branding.mjs
index eb3cd23b59..565807183d 100644
--- a/scripts/patch-crove-branding.mjs
+++ b/scripts/patch-crove-branding.mjs
@@ -294,11 +294,169 @@ export const BrandingLogoIcon = ({ className = 'h-6 w-auto', ...props }: LogoPro
}
// ==========================================
-// 5. UPDATE METADATA UTILS
+// 5. RASTERIZE BRAND BINARIES
+// ==========================================
+
+// Regenerates the committed PNG/ICO/JPG brand binaries from the Crove SVG
+// (the upstream Documenso artwork that ships with the repo would otherwise
+// keep leaking into favicons, social previews and email footers). Requires
+// sharp at the repo root; skipped gracefully when unavailable so the patch
+// never fails a fresh clone without node_modules.
+async function rasterizeBrandBinaries() {
+ console.log('🖼️ [4/5] Rasterizing Crove Sign brand binaries...');
+
+ let sharp;
+
+ try {
+ sharp = (await import('sharp')).default;
+ } catch {
+ console.log(' ⚠️ sharp not available - skipping binary rasterization (committed binaries kept)');
+ return;
+ }
+
+ const MARK_SVG = ``;
+
+ const GREEN = '#10B981';
+ const DARK = '#0f1113';
+
+ const wordmarkSvg = (
+ textColor,
+ bg,
+ ) => ``;
+
+ const ogSvg = ``;
+
+ const shareFrameSvg = (
+ accent,
+ ) => `
+
+
+ Crove
+ Sign
+ ${MARK_SVG.replace('', '').replace('', '')}
+`;
+
+ // Minimal ICO container wrapping a single PNG-compressed image (valid on
+ // Windows Vista and every browser released since).
+ const pngToIco = (pngBuffer) => {
+ const header = Buffer.alloc(6);
+ header.writeUInt16LE(0, 0);
+ header.writeUInt16LE(1, 2);
+ header.writeUInt16LE(1, 4);
+
+ const entry = Buffer.alloc(16);
+ entry.writeUInt8(32, 0);
+ entry.writeUInt8(32, 1);
+ entry.writeUInt8(0, 2);
+ entry.writeUInt8(0, 3);
+ entry.writeUInt16LE(1, 4);
+ entry.writeUInt16LE(32, 6);
+ entry.writeUInt32LE(pngBuffer.length, 8);
+ entry.writeUInt32LE(22, 12);
+
+ return Buffer.concat([header, entry, pngBuffer]);
+ };
+
+ const writeIco = async (buffer) => {
+ const png = await sharp(buffer).resize(32, 32).png().toBuffer();
+ return pngToIco(png);
+ };
+
+ const targets = [
+ ['apps/remix/public/favicon-16x16.png', 16],
+ ['apps/remix/public/favicon-32x32.png', 32],
+ ['apps/remix/public/apple-touch-icon.png', 180],
+ ['apps/remix/public/android-chrome-192x192.png', 192],
+ ['apps/remix/public/android-chrome-512x512.png', 512],
+ ];
+
+ try {
+ for (const [relPath, size] of targets) {
+ await sharp(Buffer.from(MARK_SVG)).resize(size, size).png().toFile(path.join(ROOT_DIR, relPath));
+ console.log(` ✓ ${relPath} (${size}x${size})`);
+ }
+
+ fs.writeFileSync(path.join(ROOT_DIR, 'apps/remix/public/favicon.ico'), await writeIco(Buffer.from(MARK_SVG)));
+ console.log(' ✓ apps/remix/public/favicon.ico (32x32 PNG-ICO)');
+
+ await sharp(Buffer.from(wordmarkSvg('#111311', null)))
+ .png()
+ .toFile(path.join(ROOT_DIR, 'packages/assets/static/logo.png'));
+ console.log(' ✓ packages/assets/static/logo.png (374x55 wordmark)');
+
+ // The SERVED copies live in apps/remix/public/static/ (email asset-url
+ // and the share OG composition fetch them over HTTP) - packages/assets/
+ // static/ is the source-of-record twin.
+ await sharp(Buffer.from(wordmarkSvg('#111311', null)))
+ .png()
+ .toFile(path.join(ROOT_DIR, 'apps/remix/public/static/logo.png'));
+ console.log(' ✓ apps/remix/public/static/logo.png (374x55 wordmark)');
+
+ await sharp(Buffer.from(MARK_SVG))
+ .resize(320, 320)
+ .png()
+ .toFile(path.join(ROOT_DIR, 'packages/assets/logo_icon.png'));
+ console.log(' ✓ packages/assets/logo_icon.png (320x320)');
+
+ await sharp(Buffer.from(ogSvg))
+ .jpeg({ quality: 90 })
+ .toFile(path.join(ROOT_DIR, 'apps/remix/public/opengraph-image.jpg'));
+ console.log(' ✓ apps/remix/public/opengraph-image.jpg (1270x760)');
+
+ await sharp(Buffer.from(shareFrameSvg(GREEN)))
+ .png()
+ .toFile(path.join(ROOT_DIR, 'packages/assets/static/og-share-frame.png'));
+ console.log(' ✓ packages/assets/static/og-share-frame.png (1200x630)');
+
+ await sharp(Buffer.from(shareFrameSvg(GREEN)))
+ .png()
+ .toFile(path.join(ROOT_DIR, 'apps/remix/public/static/og-share-frame.png'));
+ console.log(' ✓ apps/remix/public/static/og-share-frame.png (1200x630)');
+
+ await sharp(Buffer.from(shareFrameSvg('#34D399')))
+ .png()
+ .toFile(path.join(ROOT_DIR, 'packages/assets/static/og-share-frame2.png'));
+ console.log(' ✓ packages/assets/static/og-share-frame2.png (1200x630)');
+
+ await sharp(Buffer.from(shareFrameSvg('#34D399')))
+ .png()
+ .toFile(path.join(ROOT_DIR, 'apps/remix/public/static/og-share-frame2.png'));
+ console.log(' ✓ apps/remix/public/static/og-share-frame2.png (1200x630)');
+ } catch (error) {
+ // Degrade to the committed binaries on any sharp/libvips failure rather
+ // than failing the whole patch run.
+ console.log(` ⚠️ Rasterization failed (${error.message}) - committed binaries kept`);
+ }
+
+ console.log(' ✅ Brand binaries rasterized.\n');
+}
+
+// ==========================================
+// 6. UPDATE METADATA UTILS
// ==========================================
function patchMetadata() {
- console.log('📄 [4/4] Verifying app metadata...');
+ console.log('📄 [5/5] Verifying app metadata...');
const metaPath = path.join(ROOT_DIR, 'apps', 'remix', 'app', 'utils', 'meta.ts');
const metaContent = `import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { i18n, type MessageDescriptor } from '@lingui/core';
@@ -372,7 +530,7 @@ export const appMetaTags = (title?: MessageDescriptor) => {
// MAIN RUNNER
// ==========================================
-function main() {
+async function main() {
console.log('\n========================================');
console.log('🚀 Crove Sign - Enterprise Brand Patch');
console.log('========================================\n');
@@ -381,6 +539,7 @@ function main() {
patchTranslationCatalogs();
patchWebManifests();
generateBrandAssets();
+ await rasterizeBrandBinaries();
patchMetadata();
console.log('🎉 ALL CROVE SIGN BRANDING PATCHES APPLIED SUCCESSFULLY!\n');