diff --git a/backend/apps/cloud/src/common/templates/en/subscribe-reminder.html b/backend/apps/cloud/src/common/templates/en/subscribe-reminder.html
new file mode 100644
index 000000000..c0e18de61
--- /dev/null
+++ b/backend/apps/cloud/src/common/templates/en/subscribe-reminder.html
@@ -0,0 +1,22 @@
+Hey there,
+
+You signed up for Swetrix a couple of days ago and set up your project — nice!
+But it looks like you haven't started your free trial yet.
+
+The trial is 14 days, no credit card required, and gives you full access to
+everything Swetrix offers — unlimited features, no restrictions.
+
+Start your free trial
+
+Here's what you get:
+
+ - Web analytics that don't require cookie banners
+ - Error tracking and session analysis
+ - Custom events, funnels, and goals
+ - Privacy-first reCAPTCHA alternative
+
+
+If you have any questions or need help, just reply to this email.
+
+Andrii Romasiun
+Founder, Swetrix
diff --git a/backend/apps/cloud/src/mailer/letter.ts b/backend/apps/cloud/src/mailer/letter.ts
index d7c8cafe1..ce1e69f42 100644
--- a/backend/apps/cloud/src/mailer/letter.ts
+++ b/backend/apps/cloud/src/mailer/letter.ts
@@ -23,4 +23,5 @@ export enum LetterTemplate {
OrganisationInvitationUnregistered = 'organisation-invitation-unregistered',
SocialIdentityLinked = 'social-identity-linked',
NoEventsAfterSignup = 'no-events-after-signup',
+ SubscribeReminder = 'subscribe-reminder',
}
diff --git a/backend/apps/cloud/src/mailer/mailer.service.ts b/backend/apps/cloud/src/mailer/mailer.service.ts
index fd8824528..05d31f53a 100644
--- a/backend/apps/cloud/src/mailer/mailer.service.ts
+++ b/backend/apps/cloud/src/mailer/mailer.service.ts
@@ -134,6 +134,11 @@ const metaInfoJson = {
en: () => 'Need help setting up Swetrix?',
},
},
+ [LetterTemplate.SubscribeReminder]: {
+ subject: {
+ en: () => 'Your Swetrix trial is waiting for you',
+ },
+ },
}
interface Params {
diff --git a/backend/apps/cloud/src/task-manager/task-manager.service.ts b/backend/apps/cloud/src/task-manager/task-manager.service.ts
index e221ca556..47c8e0e88 100644
--- a/backend/apps/cloud/src/task-manager/task-manager.service.ts
+++ b/backend/apps/cloud/src/task-manager/task-manager.service.ts
@@ -1114,7 +1114,7 @@ export class TaskManagerService {
const users = await this.userService.find({
where: {
isActive: true,
- // we don't want to send the reminder for people who for example used it long time ago, then removed their projects and now are kinda counted as "new users"
+ planCode: Not(PlanCode.none),
created: Between(weekAgo, twoDaysAgo),
noEventsReminderSentOn: IsNull(),
},
@@ -1163,6 +1163,50 @@ export class TaskManagerService {
})
}
+ @Cron(CronExpression.EVERY_DAY_AT_10AM)
+ async remindUsersToSubscribe() {
+ const weekAgo = dayjs.utc().subtract(1, 'week').toDate()
+ const twoDaysAgo = dayjs
+ .utc()
+ .subtract(NO_EVENTS_REMINDER_DELAY_DAYS, 'days')
+ .toDate()
+
+ const users = await this.userService.find({
+ where: {
+ isActive: true,
+ planCode: PlanCode.none,
+ hasCompletedOnboarding: true,
+ created: Between(weekAgo, twoDaysAgo),
+ subscribeReminderSentOn: IsNull(),
+ },
+ select: ['id', 'email'],
+ })
+
+ if (_isEmpty(users)) {
+ return
+ }
+
+ const subscribeUrl = `${this.configService.get('CLIENT_URL')}/subscribe`
+ const sentOn = dayjs.utc().format('YYYY-MM-DD HH:mm:ss')
+
+ await mapLimit(users, REPORTS_USERS_CONCURRENCY, async (user) => {
+ try {
+ await this.mailerService.sendEmail(
+ user.email,
+ LetterTemplate.SubscribeReminder,
+ { subscribeUrl },
+ )
+ await this.userService.update(user.id, {
+ subscribeReminderSentOn: sentOn,
+ })
+ } catch (reason) {
+ this.logger.error(
+ `[CRON WORKER](remindUsersToSubscribe) Failed to process user ${user.id}: ${reason}`,
+ )
+ }
+ })
+ }
+
@Cron(CronExpression.EVERY_2_HOURS)
async deleteOldShareInvitations() {
const minDate = dayjs.utc().subtract(PROJECT_INVITE_EXPIRE, 'h').toDate()
diff --git a/backend/apps/cloud/src/user/entities/user.entity.ts b/backend/apps/cloud/src/user/entities/user.entity.ts
index 4d3a4d9d1..1dda90654 100644
--- a/backend/apps/cloud/src/user/entities/user.entity.ts
+++ b/backend/apps/cloud/src/user/entities/user.entity.ts
@@ -274,6 +274,10 @@ export class User {
@Column({ type: 'timestamp', nullable: true })
noEventsReminderSentOn: Date
+ // the date when the "you haven't subscribed yet" reminder email was sent
+ @Column({ type: 'timestamp', nullable: true })
+ subscribeReminderSentOn: Date
+
@Column('varchar', { length: 15, nullable: true })
subID: string
diff --git a/backend/migrations/mysql/2026_03_10_subscribe_reminder.sql b/backend/migrations/mysql/2026_03_10_subscribe_reminder.sql
new file mode 100644
index 000000000..8759b24af
--- /dev/null
+++ b/backend/migrations/mysql/2026_03_10_subscribe_reminder.sql
@@ -0,0 +1 @@
+ALTER TABLE `user` ADD COLUMN `subscribeReminderSentOn` timestamp DEFAULT NULL;