diff --git a/src/remote/activitypub/kernel/undo/index.ts b/src/remote/activitypub/kernel/undo/index.ts
index ba56dd6328..471988f052 100644
--- a/src/remote/activitypub/kernel/undo/index.ts
+++ b/src/remote/activitypub/kernel/undo/index.ts
@@ -1,9 +1,10 @@
 import * as debug from 'debug';
 
 import { IRemoteUser } from '../../../../models/user';
-import { IUndo, IFollow, IBlock } from '../../type';
+import { IUndo, IFollow, IBlock, ILike } from '../../type';
 import unfollow from './follow';
 import unblock from './block';
+import undoLike from './like';
 import Resolver from '../../resolver';
 
 const log = debug('misskey:activitypub');
@@ -35,6 +36,9 @@ export default async (actor: IRemoteUser, activity: IUndo): Promise<void> => {
 		case 'Block':
 			unblock(actor, object as IBlock);
 			break;
+		case 'Like':
+			undoLike(actor, object as ILike);
+			break;
 	}
 
 	return null;
diff --git a/src/remote/activitypub/kernel/undo/like.ts b/src/remote/activitypub/kernel/undo/like.ts
new file mode 100644
index 0000000000..b324ec854c
--- /dev/null
+++ b/src/remote/activitypub/kernel/undo/like.ts
@@ -0,0 +1,21 @@
+import * as mongo from 'mongodb';
+import { IRemoteUser } from '../../../../models/user';
+import { ILike } from '../../type';
+import Note from '../../../../models/note';
+import deleteReaction from '../../../../services/note/reaction/delete';
+
+/**
+ * Process Undo.Like activity
+ */
+export default async (actor: IRemoteUser, activity: ILike): Promise<void> => {
+	const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
+
+	const noteId = new mongo.ObjectID(id.split('/').pop());
+
+	const note = await Note.findOne({ _id: noteId });
+	if (note === null) {
+		throw 'note not found';
+	}
+
+	await deleteReaction(actor, note);
+};
diff --git a/src/server/api/common/getters.ts b/src/server/api/common/getters.ts
new file mode 100644
index 0000000000..1fce58b20a
--- /dev/null
+++ b/src/server/api/common/getters.ts
@@ -0,0 +1,18 @@
+import * as mongo from 'mongodb';
+import Note from "../../../models/note";
+
+/**
+ * Get valied note for API processing
+ */
+export async function getValiedNote(noteId: mongo.ObjectID) {
+	const note = await Note.findOne({
+		_id: noteId,
+		deletedAt: { $exists: false }
+	});
+
+	if (note === null) {
+		throw 'note not found';
+	}
+
+	return note;
+}
diff --git a/src/server/api/endpoints/notes/reactions/create.ts b/src/server/api/endpoints/notes/reactions/create.ts
index 6c90898250..4037e89943 100644
--- a/src/server/api/endpoints/notes/reactions/create.ts
+++ b/src/server/api/endpoints/notes/reactions/create.ts
@@ -1,8 +1,10 @@
+import * as mongo from 'mongodb';
 import $ from 'cafy'; import ID, { transform } from '../../../../../misc/cafy-id';
-import Note from '../../../../../models/note';
-import create from '../../../../../services/note/reaction/create';
+import createReaction from '../../../../../services/note/reaction/create';
 import { validateReaction } from '../../../../../models/note-reaction';
 import define from '../../../define';
+import { IUser } from '../../../../../models/user';
+import { getValiedNote } from '../../../common/getters';
 
 export const meta = {
 	stability: 'stable',
@@ -34,25 +36,12 @@ export const meta = {
 	}
 };
 
-export default define(meta, (ps, user) => new Promise(async (res, rej) => {
-	// Fetch reactee
-	const note = await Note.findOne({
-		_id: ps.noteId
-	});
-
-	if (note === null) {
-		return rej('note not found');
-	}
-
-	if (note.deletedAt != null) {
-		return rej('this note is already deleted');
-	}
-
-	try {
-		await create(user, note, ps.reaction);
-	} catch (e) {
-		rej(e);
-	}
-
-	res();
+export default define(meta, (ps, user) => new Promise((res, rej) => {
+	createReactionById(user, ps.noteId, ps.reaction)
+		.then(r => res(r)).catch(e => rej(e));
 }));
+
+async function createReactionById(user: IUser, noteId: mongo.ObjectID, reaction: string) {
+	const note = await getValiedNote(noteId);
+	await createReaction(user, note, reaction);
+}
diff --git a/src/server/api/endpoints/notes/reactions/delete.ts b/src/server/api/endpoints/notes/reactions/delete.ts
index 40139afee1..9ff4edb7f5 100644
--- a/src/server/api/endpoints/notes/reactions/delete.ts
+++ b/src/server/api/endpoints/notes/reactions/delete.ts
@@ -1,9 +1,10 @@
+import * as mongo from 'mongodb';
 import $ from 'cafy'; import ID, { transform } from '../../../../../misc/cafy-id';
-import Reaction from '../../../../../models/note-reaction';
-import Note from '../../../../../models/note';
 import define from '../../../define';
-import { publishNoteStream } from '../../../../../stream';
 const ms = require('ms');
+import deleteReaction from '../../../../../services/note/reaction/delete';
+import { IUser } from '../../../../../models/user';
+import { getValiedNote } from '../../../common/getters';
 
 export const meta = {
 	desc: {
@@ -33,44 +34,12 @@ export const meta = {
 	}
 };
 
-export default define(meta, (ps, user) => new Promise(async (res, rej) => {
-	// Fetch unreactee
-	const note = await Note.findOne({
-		_id: ps.noteId
-	});
-
-	if (note === null) {
-		return rej('note not found');
-	}
-
-	// if already unreacted
-	const exist = await Reaction.findOne({
-		noteId: note._id,
-		userId: user._id,
-		deletedAt: { $exists: false }
-	});
-
-	if (exist === null) {
-		return rej('never reacted');
-	}
-
-	// Delete reaction
-	await Reaction.remove({
-		_id: exist._id
-	});
-
-	res();
-
-	const dec: any = {};
-	dec[`reactionCounts.${exist.reaction}`] = -1;
-
-	// Decrement reactions count
-	Note.update({ _id: note._id }, {
-		$inc: dec
-	});
-
-	publishNoteStream(note._id, 'unreacted', {
-		reaction: exist.reaction,
-		userId: user._id
-	});
+export default define(meta, (ps, user) => new Promise((res, rej) => {
+	deleteReactionById(user, ps.noteId)
+		.then(r => res(r)).catch(e => rej(e));
 }));
+
+async function deleteReactionById(user: IUser, noteId: mongo.ObjectID) {
+	const note = await getValiedNote(noteId);
+	await deleteReaction(user, note);
+}
diff --git a/src/services/note/reaction/delete.ts b/src/services/note/reaction/delete.ts
new file mode 100644
index 0000000000..b108f0ba75
--- /dev/null
+++ b/src/services/note/reaction/delete.ts
@@ -0,0 +1,49 @@
+import { IUser, isLocalUser, isRemoteUser } from '../../../models/user';
+import Note, { INote } from '../../../models/note';
+import Reaction from '../../../models/note-reaction';
+import { publishNoteStream } from '../../../stream';
+import renderLike from '../../../remote/activitypub/renderer/like';
+import renderUndo from '../../../remote/activitypub/renderer/undo';
+import pack from '../../../remote/activitypub/renderer';
+import { deliver } from '../../../queue';
+
+export default async (user: IUser, note: INote) => new Promise(async (res, rej) => {
+	// if already unreacted
+	const exist = await Reaction.findOne({
+		noteId: note._id,
+		userId: user._id,
+		deletedAt: { $exists: false }
+	});
+
+	if (exist === null) {
+		return rej('never reacted');
+	}
+
+	// Delete reaction
+	await Reaction.remove({
+		_id: exist._id
+	});
+
+	res();
+
+	const dec: any = {};
+	dec[`reactionCounts.${exist.reaction}`] = -1;
+
+	// Decrement reactions count
+	Note.update({ _id: note._id }, {
+		$inc: dec
+	});
+
+	publishNoteStream(note._id, 'unreacted', {
+		reaction: exist.reaction,
+		userId: user._id
+	});
+
+	//#region 配信
+	// リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送
+	if (isLocalUser(user) && isRemoteUser(note._user)) {
+		const content = pack(renderUndo(renderLike(user, note, exist.reaction), user));
+		deliver(user, content, note._user.inbox);
+	}
+	//#endregion
+});