diff --git a/lib/util/emoji.spec.ts b/lib/util/emoji.spec.ts
index b8b15a9660c913d9e971ed2d7656d91b42e1fab9..5c7083d7b284ce6edbf5c5419643b05cb3b6cc28 100644
--- a/lib/util/emoji.spec.ts
+++ b/lib/util/emoji.spec.ts
@@ -1,22 +1,87 @@
+import { fromCodepointToUnicode, fromHexcodeToCodepoint } from 'emojibase';
 import { getName } from '../../test/util';
-import { setEmojiConfig, unemojify } from './emoji';
+import { emojify, setEmojiConfig, stripEmojis, unemojify } from './emoji';
 
 describe(getName(), () => {
-  it('strips emojis when the config has been set accordingly', () => {
-    const emoji = '🚀💎';
-    const otherText = 'regular text';
-    const text = `${emoji} ${otherText}`;
-    setEmojiConfig({ unicodeEmoji: false });
-    const result = unemojify(text);
-    expect(result).not.toContain(emoji);
+  beforeEach(() => {
+    setEmojiConfig({ unicodeEmoji: true });
   });
 
-  it('does not strip emojis when the config demands it', () => {
-    const emoji = '🚀💎';
-    const otherText = 'regular text';
-    const text = `${emoji} ${otherText}`;
-    setEmojiConfig({ unicodeEmoji: true });
-    const result = unemojify(text);
-    expect(result).toEqual(text);
+  describe('emojify', () => {
+    it('encodes known shortcodes', () => {
+      expect(emojify('Let it :bee:')).toEqual('Let it 🐝');
+    });
+
+    it('encodes aliases', () => {
+      const bee = emojify(':bee:');
+      const honeyBee = emojify(':honeybee:');
+      expect(bee).toEqual(honeyBee);
+    });
+
+    it('omits unknown shortcodes', () => {
+      expect(emojify(':foo: :bar: :bee:')).toEqual(':foo: :bar: 🐝');
+    });
+
+    it('does not encode when config option is disabled', () => {
+      setEmojiConfig({ unicodeEmoji: false });
+      expect(emojify('Let it :bee:')).toEqual('Let it :bee:');
+    });
+  });
+
+  describe('unemojify', () => {
+    it('strips emojis when the config has been set accordingly', () => {
+      const emoji = '🚀💎';
+      const otherText = 'regular text';
+      const text = `${emoji} ${otherText}`;
+      setEmojiConfig({ unicodeEmoji: false });
+      const result = unemojify(text);
+      expect(result).not.toContain(emoji);
+    });
+
+    it('does not strip emojis when the config demands it', () => {
+      const emoji = '🚀💎';
+      const otherText = 'regular text';
+      const text = `${emoji} ${otherText}`;
+      setEmojiConfig({ unicodeEmoji: true });
+      const result = unemojify(text);
+      expect(result).toEqual(text);
+    });
+
+    describe('unsupported characters', () => {
+      const unsupported = '🪆';
+
+      it('uses replacement character', () => {
+        setEmojiConfig({ unicodeEmoji: false });
+        expect(unemojify(unsupported)).toEqual('�');
+      });
+    });
+  });
+
+  describe('problem characters', () => {
+    it.each(['🚀', '💎', '🧹', '📦'])('converts %s forth and back', (char) => {
+      setEmojiConfig({ unicodeEmoji: false });
+      const codified = unemojify(char);
+      expect(codified).not.toEqual(char);
+
+      setEmojiConfig({ unicodeEmoji: true });
+      const emojified = emojify(codified);
+      expect(emojified).toEqual(char);
+    });
+  });
+
+  describe('stripEmojis', () => {
+    const makeEmoji = (hexCode: string): string =>
+      fromCodepointToUnicode(fromHexcodeToCodepoint(hexCode));
+
+    it('is independent of config option', () => {
+      const x: string = makeEmoji('26A0-FE0F');
+      const y: string = makeEmoji('26A0');
+
+      setEmojiConfig({ unicodeEmoji: true });
+      expect(stripEmojis(`foo ${x} bar`)).toEqual(`foo ${y} bar`);
+
+      setEmojiConfig({ unicodeEmoji: false });
+      expect(stripEmojis(`foo ${x} bar`)).toEqual(`foo ${y} bar`);
+    });
   });
 });
diff --git a/lib/util/emoji.ts b/lib/util/emoji.ts
index ff21eed5aca9fed3571c5a5dc3ff603ddf28f59f..9e2a8b73ea93e96d27fc83c56199c286c8f87f90 100644
--- a/lib/util/emoji.ts
+++ b/lib/util/emoji.ts
@@ -1,16 +1,103 @@
-import emoji from 'node-emoji';
+import is from '@sindresorhus/is';
+import mathiasBynensEmojiRegex from 'emoji-regex';
+import {
+  fromCodepointToUnicode,
+  fromHexcodeToCodepoint,
+  fromUnicodeToHexcode,
+} from 'emojibase';
+import emojibaseEmojiRegex from 'emojibase-regex/emoji';
+import SHORTCODE_REGEX from 'emojibase-regex/shortcode';
 import type { RenovateConfig } from '../config/types';
+import dataFiles from '../data-files.generated';
+import { regEx } from './regex';
 
 let unicodeEmoji = true;
 
+let mappingsInitialized = false;
+const shortCodesByHex = new Map<string, string>();
+const hexCodesByShort = new Map<string, string>();
+
+function lazyInitMappings(): void {
+  if (!mappingsInitialized) {
+    const table: Record<string, string | string[]> = JSON.parse(
+      dataFiles.get('node_modules/emojibase-data/en/shortcodes/github.json')
+    );
+    for (const [hex, val] of Object.entries(table)) {
+      const shortCodes: string[] = is.array<string>(val) ? val : [val];
+      shortCodesByHex.set(hex, `:${shortCodes[0]}:`);
+      shortCodes.forEach((shortCode) => {
+        hexCodesByShort.set(`:${shortCode}:`, hex);
+      });
+    }
+    mappingsInitialized = true;
+  }
+}
+
 export function setEmojiConfig(_config: RenovateConfig): void {
   unicodeEmoji = _config.unicodeEmoji;
 }
 
+const shortCodeRegex = regEx(SHORTCODE_REGEX.source, 'g');
+
 export function emojify(text: string): string {
-  return unicodeEmoji ? emoji.emojify(text) : text;
+  if (!unicodeEmoji) {
+    return text;
+  }
+  lazyInitMappings();
+  return text.replace(shortCodeRegex, (shortCode) => {
+    const hexCode = hexCodesByShort.get(shortCode);
+    return hexCode
+      ? fromCodepointToUnicode(fromHexcodeToCodepoint(hexCode))
+      : shortCode;
+  });
+}
+
+const emojiRegexSrc = [emojibaseEmojiRegex, mathiasBynensEmojiRegex()].map(
+  ({ source }) => source
+);
+const emojiRegex = new RegExp(`(?:${emojiRegexSrc.join('|')})`, 'g');
+const excludedModifiers = new Set([
+  '20E3',
+  '200D',
+  'FE0E',
+  'FE0F',
+  '1F3FB',
+  '1F3FC',
+  '1F3FD',
+  '1F3FE',
+  '1F3FF',
+  '1F9B0',
+  '1F9B1',
+  '1F9B2',
+  '1F9B3',
+]);
+
+export function stripHexCode(input: string): string {
+  return input
+    .split('-')
+    .filter((modifier) => !excludedModifiers.has(modifier))
+    .join('-');
 }
 
 export function unemojify(text: string): string {
-  return unicodeEmoji ? text : emoji.unemojify(text);
+  if (unicodeEmoji) {
+    return text;
+  }
+  lazyInitMappings();
+  return text.replace(emojiRegex, (emoji) => {
+    const hexCode = stripHexCode(fromUnicodeToHexcode(emoji));
+    const shortCode = shortCodesByHex.get(hexCode);
+    return shortCode || '�';
+  });
+}
+
+function stripEmoji(emoji: string): string {
+  const hexCode = stripHexCode(fromUnicodeToHexcode(emoji));
+  const codePoint = fromHexcodeToCodepoint(hexCode);
+  const result = fromCodepointToUnicode(codePoint);
+  return result;
+}
+
+export function stripEmojis(input: string): string {
+  return input.replace(emojiRegex, stripEmoji);
 }
diff --git a/lib/workers/pr/__snapshots__/index.spec.ts.snap b/lib/workers/pr/__snapshots__/index.spec.ts.snap
index f3ac046eb730fd49d2eede6b301b5823afe46fec..19997363f4e8a00168d4b1e8b4ffb9e54b620779 100644
--- a/lib/workers/pr/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/pr/__snapshots__/index.spec.ts.snap
@@ -64,7 +64,7 @@ Array [
       "bbUseDefaultReviewers": true,
       "gitLabAutomerge": false,
     },
-    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | pin | \`1.0.0\` -> \`1.1.0\` |\\n\\n📌 **Important**: Renovate will wait until you have merged this Pin PR before creating any *upgrade* PRs for the affected packages. Add the preset \`:preserveSemverRanges\` to your config if you instead don't wish to pin dependencies.\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" in timezone some timezone.\\n\\n🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.\\n\\n♻️ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
+    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | pin | \`1.0.0\` -> \`1.1.0\` |\\n\\n📌 **Important**: Renovate will wait until you have merged this Pin PR before creating any *upgrade* PRs for the affected packages. Add the preset \`:preserveSemverRanges\` to your config if you instead don't wish to pin dependencies.\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" in timezone some timezone.\\n\\n🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.\\n\\n♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
     "prTitle": "Update dependency dummy to v1.1.0",
     "sourceBranch": "renovate/dummy-1.x",
     "targetBranch": undefined,
@@ -97,7 +97,7 @@ Array [
       "bbUseDefaultReviewers": true,
       "gitLabAutomerge": false,
     },
-    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻️ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
+    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
     "prTitle": "Update dependency dummy to v1.1.0",
     "sourceBranch": "renovate/dummy-1.x",
     "targetBranch": undefined,
@@ -117,7 +117,7 @@ Array [
       "bbUseDefaultReviewers": true,
       "gitLabAutomerge": false,
     },
-    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [gitlabdummy](https://dummy.com) ([source](https://gitlab.com/renovateapp/gitlabdummy), [changelog](https://gitlab.com/renovateapp/gitlabdummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻️ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
+    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [gitlabdummy](https://dummy.com) ([source](https://gitlab.com/renovateapp/gitlabdummy), [changelog](https://gitlab.com/renovateapp/gitlabdummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
     "prTitle": "Update dependency dummy to v1.1.0",
     "sourceBranch": "renovate/gitlabdummy-1.x",
     "targetBranch": undefined,
@@ -137,7 +137,7 @@ Array [
       "bbUseDefaultReviewers": true,
       "gitLabAutomerge": false,
     },
-    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | lockFileMaintenance | \`1.0.0\` -> \`1.1.0\` |\\n| a |  |  | \`zzzzzz\` -> \`aaaaaaa\` |\\n| b |  | pin | \`some_old_value\` -> \`some_new_value\` |\\n| c |  |  | \`\` -> \`\` |\\n| d |  | lockFileMaintenance | \`\` -> \`\` |\\n\\nnote 1\\n\\nnote 2\\n\\n:warning: Release Notes retrieval for this PR were skipped because no github.com credentials were available.\\nIf you are using the hosted GitLab app, please follow [this guide](https://docs.renovatebot.com/install-gitlab-app/#configuring-a-token-for-githubcom-hosted-release-notes). If you are self-hosted, please see [this instruction](https://github.com/renovatebot/renovate/blob/master/docs/usage/self-hosting.md#githubcom-token-for-release-notes) instead.\\n\\n🔡 If you wish to disable git hash updates, add \`\\":disableDigestUpdates\\"\` to the extends array in your config.\\n\\n🔧 This Pull Request updates lock files to use the latest dependency versions.\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: At any time (no schedule defined).\\n\\n🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.\\n\\n♻️ **Rebasing**: Never, or you tick the rebase/retry checkbox.\\n\\n👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
+    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | lockFileMaintenance | \`1.0.0\` -> \`1.1.0\` |\\n| a |  |  | \`zzzzzz\` -> \`aaaaaaa\` |\\n| b |  | pin | \`some_old_value\` -> \`some_new_value\` |\\n| c |  |  | \`\` -> \`\` |\\n| d |  | lockFileMaintenance | \`\` -> \`\` |\\n\\nnote 1\\n\\nnote 2\\n\\n:warning: Release Notes retrieval for this PR were skipped because no github.com credentials were available.\\nIf you are using the hosted GitLab app, please follow [this guide](https://docs.renovatebot.com/install-gitlab-app/#configuring-a-token-for-githubcom-hosted-release-notes). If you are self-hosted, please see [this instruction](https://github.com/renovatebot/renovate/blob/master/docs/usage/self-hosting.md#githubcom-token-for-release-notes) instead.\\n\\n🔡 If you wish to disable git hash updates, add \`\\":disableDigestUpdates\\"\` to the extends array in your config.\\n\\n🔧 This Pull Request updates lock files to use the latest dependency versions.\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: At any time (no schedule defined).\\n\\n🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.\\n\\n♻ **Rebasing**: Never, or you tick the rebase/retry checkbox.\\n\\n👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
     "prTitle": "Update dependency dummy to v1.1.0",
     "sourceBranch": "renovate/dummy-1.x",
     "targetBranch": undefined,
@@ -157,7 +157,7 @@ Array [
       "bbUseDefaultReviewers": true,
       "gitLabAutomerge": false,
     },
-    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>someproject</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: At any time (no schedule defined).\\n\\n🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.\\n\\n♻️ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
+    "prBody": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>someproject</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: At any time (no schedule defined).\\n\\n🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.\\n\\n♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
     "prTitle": "Update dependency dummy to v1.1.0",
     "sourceBranch": "renovate/dummy-1.x",
     "targetBranch": undefined,
@@ -231,7 +231,7 @@ Array [
 
 exports[`workers/pr/index ensurePr should return modified existing PR 1`] = `
 Object {
-  "body": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻️ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
+  "body": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
   "displayNumber": "Existing PR",
   "title": "Update dependency dummy to v1.1.0",
 }
@@ -239,7 +239,7 @@ Object {
 
 exports[`workers/pr/index ensurePr should return modified existing PR title 1`] = `
 Object {
-  "body": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻️ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
+  "body": "This PR contains the following updates:\\n\\n| Package | Type | Update | Change |\\n|---|---|---|---|\\n| [dummy](https://dummy.com) ([source](https://github.com/renovateapp/dummy), [changelog](https://github.com/renovateapp/dummy/changelog.md)) | devDependencies | minor | \`1.0.0\` -> \`1.1.0\` |\\n\\n---\\n\\n### Release Notes\\n\\n<details>\\n<summary>renovateapp/dummy</summary>\\n\\n### [\`v1.1.0\`](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n[Compare Source](https://github.com/renovateapp/dummy/compare/v1.0.0...v1.1.0)\\n\\n</details>\\n\\n---\\n\\n### Configuration\\n\\n📅 **Schedule**: \\"before 5am\\" (UTC).\\n\\n🚦 **Automerge**: Enabled.\\n\\n♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.\\n\\n🔕 **Ignore**: Close this PR and you won't be reminded about this update again.\\n\\n---\\n\\n - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.\\n\\n---\\n\\nThis PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
   "displayNumber": "Existing PR",
   "title": "wrong",
 }
diff --git a/lib/workers/pr/body/__snapshots__/controls.spec.ts.snap b/lib/workers/pr/body/__snapshots__/controls.spec.ts.snap
index 41e5203f65f86fad9e50b8e494ab3f39e02d7f0b..63dd7e7a0066abc5254aae215f731cca90cdd16c 100644
--- a/lib/workers/pr/body/__snapshots__/controls.spec.ts.snap
+++ b/lib/workers/pr/body/__snapshots__/controls.spec.ts.snap
@@ -5,7 +5,7 @@ exports[`workers/pr/body/controls getControls when the branch is  modified has t
 
 ---
 
- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box. ⚠️ **Warning**: custom changes will be lost.
+ - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box. âš  **Warning**: custom changes will be lost.
 
 "
 `;
diff --git a/lib/workers/pr/body/controls.ts b/lib/workers/pr/body/controls.ts
index 5d7d5943f7927022a57a0c1ca29620641f6b9ba0..2ee42f83560c96e28e72ee6ff22626d2ae64e852 100644
--- a/lib/workers/pr/body/controls.ts
+++ b/lib/workers/pr/body/controls.ts
@@ -1,4 +1,4 @@
-import { emojify } from 'node-emoji';
+import { emojify } from '../../../util/emoji';
 import { isBranchModified } from '../../../util/git';
 import { BranchConfig } from '../../types';
 
diff --git a/lib/workers/pr/index.ts b/lib/workers/pr/index.ts
index 9d7cbbf3ce887352eb74058810e7da8adfdbd4fc..d5a92eb901e08ab88a3ee71c112619c1374cb726 100644
--- a/lib/workers/pr/index.ts
+++ b/lib/workers/pr/index.ts
@@ -10,6 +10,7 @@ import { PlatformPrOptions, Pr, platform } from '../../platform';
 import { BranchStatus } from '../../types';
 import { ExternalHostError } from '../../types/errors/external-host-error';
 import { sampleSize } from '../../util';
+import { stripEmojis } from '../../util/emoji';
 import { deleteBranch, getBranchLastCommitTime } from '../../util/git';
 import * as template from '../../util/template';
 import { Limit, incLimitedValue, isLimitReached } from '../global/limits';
@@ -341,17 +342,19 @@ export async function ensurePr(
         logger.debug('Stripping Reviewable content');
         existingPrBody = existingPrBody.slice(0, reviewableIndex);
       }
+      const existingPrTitle = stripEmojis(existingPr.title);
+      const newPrTitle = stripEmojis(prTitle);
       existingPrBody = existingPrBody.trim();
       if (
-        existingPr.title === prTitle &&
-        noWhitespaceOrHeadings(existingPrBody) ===
-          noWhitespaceOrHeadings(prBody)
+        existingPrTitle === newPrTitle &&
+        noWhitespaceOrHeadings(stripEmojis(existingPrBody)) ===
+          noWhitespaceOrHeadings(stripEmojis(prBody))
       ) {
         logger.debug(`${existingPr.displayNumber} does not need updating`);
         return { prResult: PrResult.NotUpdated, pr: existingPr };
       }
       // PR must need updating
-      if (existingPr.title !== prTitle) {
+      if (existingPrTitle !== newPrTitle) {
         logger.debug(
           {
             branchName,
diff --git a/lib/workers/repository/onboarding/pr/__snapshots__/errors-warnings.spec.ts.snap b/lib/workers/repository/onboarding/pr/__snapshots__/errors-warnings.spec.ts.snap
index ba787dda8c7639f1102b8143d67fa15c0886244f..0262a1986aaba4697372518d12772fb69f0c10d6 100644
--- a/lib/workers/repository/onboarding/pr/__snapshots__/errors-warnings.spec.ts.snap
+++ b/lib/workers/repository/onboarding/pr/__snapshots__/errors-warnings.spec.ts.snap
@@ -4,7 +4,7 @@ exports[`workers/repository/onboarding/pr/errors-warnings getDepWarnings() retur
 "
 ---
 
-### ⚠️ Dependency Lookup Warnings ⚠️
+### âš  Dependency Lookup Warnings âš 
 
 Please correct - or verify that you can safely ignore - these lookup failures before you merge this PR.
 
diff --git a/package.json b/package.json
index 00230ebed72469fb297d443f898a099e3af52c3f..8a4ac3f1d3d0e0b3bf21be3719a2c0adc8371ef1 100644
--- a/package.json
+++ b/package.json
@@ -144,6 +144,9 @@
     "dequal": "2.0.2",
     "detect-indent": "6.0.0",
     "email-addresses": "4.0.0",
+    "emoji-regex": "9.2.2",
+    "emojibase": "5.1.1",
+    "emojibase-regex": "5.1.2",
     "fast-safe-stringify": "2.0.7",
     "find-up": "5.0.0",
     "fs-extra": "10.0.0",
@@ -165,7 +168,6 @@
     "markdown-table": "2.0.0",
     "minimatch": "3.0.4",
     "moo": "0.5.1",
-    "node-emoji": "1.10.0",
     "node-html-parser": "3.3.4",
     "p-all": "3.0.0",
     "p-map": "4.0.0",
@@ -235,6 +237,7 @@
     "@typescript-eslint/parser": "4.25.0",
     "conventional-changelog-conventionalcommits": "4.6.0",
     "cross-env": "7.0.3",
+    "emojibase-data": "6.1.2",
     "eslint": "7.27.0",
     "eslint-config-airbnb-typescript": "12.3.1",
     "eslint-config-prettier": "8.3.0",
diff --git a/tools/generate-imports.mjs b/tools/generate-imports.mjs
index db13c8cddd318700cdb5ae6a5425960733f1a0cb..4633a0d09e64408b5b9086c282a887b1637475bd 100644
--- a/tools/generate-imports.mjs
+++ b/tools/generate-imports.mjs
@@ -28,7 +28,10 @@ async function updateFile(file, code) {
   newFiles.add(file);
 }
 
-const dataPaths = ['data'];
+const dataPaths = [
+  'data',
+  'node_modules/emojibase-data/en/shortcodes/github.json',
+];
 
 /**
  *
diff --git a/yarn.lock b/yarn.lock
index 6ce0a1037a84c676f3cbe48ce3721f25eae61708..70e235dc7792a08db4280f5b5f1b66155cbca3e5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3696,11 +3696,31 @@ emittery@^0.8.1:
   resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
   integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
 
+emoji-regex@9.2.2:
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+  integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
 emoji-regex@^8.0.0:
   version "8.0.0"
   resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
   integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
 
+emojibase-data@6.1.2:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/emojibase-data/-/emojibase-data-6.1.2.tgz#c30331602419239579c0d7a032fa1232d8dc298f"
+  integrity sha512-1fYgpAYkAJq7bmGO3XboP0dQHrtRiyWrAluCmv5NHSK1nruz0x8kXhpLiz48rAJGDQOWYUpLGaPASTNXVZX87Q==
+
+emojibase-regex@5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/emojibase-regex/-/emojibase-regex-5.1.2.tgz#96cc95e26b186866de1c42a16782d3242cc29c11"
+  integrity sha512-/n1k9npdzvJecnTy7qu324btGxWSi4GC4Uk9R4DLDc8CIuNx+a2RQLrDSL/0kOi0dIg4lP4h65wKICYGjyIDbw==
+
+emojibase@5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/emojibase/-/emojibase-5.1.1.tgz#fe812023959cb60d0b1b6da16042b180c96c2b7c"
+  integrity sha512-qc/qfuzZ93xmYMhnVA15yP2k3t4zJvBbqCc8dpDXFf75eJ+IogbzJuWQur8fkwsZ0u7YvJDBh939F9DapQqktQ==
+
 encoding@^0.1.12:
   version "0.1.13"
   resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
@@ -6906,7 +6926,7 @@ nock@13.0.11:
     lodash.set "^4.3.2"
     propagate "^2.0.0"
 
-node-emoji@1.10.0, node-emoji@^1.10.0:
+node-emoji@^1.10.0:
   version "1.10.0"
   resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da"
   integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==