diff --git a/services/lemmy/lemmy.service.js b/services/lemmy/lemmy.service.js
new file mode 100644
index 0000000000000000000000000000000000000000..c8ff71ea21abe81ca572d9f830900a5c12489fb7
--- /dev/null
+++ b/services/lemmy/lemmy.service.js
@@ -0,0 +1,72 @@
+import Joi from 'joi'
+import { metric } from '../text-formatters.js'
+import { BaseJsonService, InvalidParameter } from '../index.js'
+
+const lemmyCommunitySchema = Joi.object({
+  community_view: Joi.object({
+    counts: Joi.object({
+      subscribers: Joi.number().required(),
+    }).required(),
+  }).required(),
+}).required()
+
+export default class Lemmy extends BaseJsonService {
+  static category = 'social'
+
+  static route = {
+    base: 'lemmy',
+    pattern: ':community',
+  }
+
+  static examples = [
+    {
+      title: 'Lemmy',
+      namedParams: { community: 'asklemmy@lemmy.ml' },
+      staticPreview: this.render({
+        community: 'asklemmy@lemmy.ml',
+        members: 42,
+      }),
+    },
+  ]
+
+  static defaultBadgeData = { label: 'community' }
+
+  static render({ community, members }) {
+    return {
+      label: `subscribe to ${community}`,
+      message: metric(members),
+      color: 'brightgreen',
+    }
+  }
+
+  async fetch({ community }) {
+    const splitAlias = community.split('@')
+    // The community will be in the format of `community@server`
+    if (splitAlias.length !== 2) {
+      throw new InvalidParameter({
+        prettyMessage: 'invalid community',
+      })
+    }
+
+    const host = splitAlias[1]
+
+    const data = await this._requestJson({
+      url: `https://${host}/api/v3/community`,
+      schema: lemmyCommunitySchema,
+      options: {
+        searchParams: {
+          name: community,
+        },
+      },
+      httpErrors: {
+        404: 'community not found',
+      },
+    })
+    return data.community_view.counts.subscribers
+  }
+
+  async handle({ community }) {
+    const members = await this.fetch({ community })
+    return this.constructor.render({ community, members })
+  }
+}
diff --git a/services/lemmy/lemmy.tester.js b/services/lemmy/lemmy.tester.js
new file mode 100644
index 0000000000000000000000000000000000000000..b4b3ad2bfdc2d771630231bb318dcf82e5e7af00
--- /dev/null
+++ b/services/lemmy/lemmy.tester.js
@@ -0,0 +1,69 @@
+import Joi from 'joi'
+import { createServiceTester } from '../tester.js'
+export const t = await createServiceTester()
+
+t.create('get community subscribers')
+  .get('/community@DUMMY.dumb.json')
+  .intercept(nock =>
+    nock('https://DUMMY.dumb/')
+      .get('/api/v3/community?name=community%40DUMMY.dumb')
+      .reply(
+        200,
+        JSON.stringify({
+          community_view: {
+            counts: {
+              subscribers: 42,
+              posts: 0,
+              comments: 0,
+            },
+          },
+        }),
+      ),
+  )
+  .expectBadge({
+    label: 'subscribe to community@DUMMY.dumb',
+    message: '42',
+    color: 'brightgreen',
+  })
+
+t.create('bad server or connection')
+  .get('/community@DUMMY.dumb.json')
+  .networkOff()
+  .expectBadge({
+    label: 'community',
+    message: 'inaccessible',
+    color: 'lightgrey',
+  })
+
+t.create('unknown community')
+  .get('/community@DUMMY.dumb.json')
+  .intercept(nock =>
+    nock('https://DUMMY.dumb/')
+      .get('/api/v3/community?name=community%40DUMMY.dumb')
+      .reply(
+        404,
+        JSON.stringify({
+          error: 'couldnt_find_community',
+        }),
+      ),
+  )
+  .expectBadge({
+    label: 'community',
+    message: 'community not found',
+    color: 'red',
+  })
+
+t.create('invalid community').get('/ALIASDUMMY.dumb.json').expectBadge({
+  label: 'community',
+  message: 'invalid community',
+  color: 'red',
+})
+
+t.create('test on real lemmy room for API compliance')
+  .get('/asklemmy@lemmy.ml.json')
+  .timeout(10000)
+  .expectBadge({
+    label: 'subscribe to asklemmy@lemmy.ml',
+    message: Joi.string().regex(/^[0-9]+k$/),
+    color: 'brightgreen',
+  })