diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 9ea036ee57..d187f683f7 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -18,11 +18,11 @@ SPDX-License-Identifier: AGPL-3.0-only
 	<!--<div v-if="appearNote._featuredId_" class="tip"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>-->
 	<div v-if="isRenote" :class="$style.renote">
 		<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
-		<MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/>
+		<MkAvatar :class="$style.renoteAvatar" :user="note.user" link :preview="!inEmbedPage && !mock"/>
 		<i class="ti ti-repeat" style="margin-right: 4px;"></i>
 		<I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText">
 			<template #user>
-				<MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
+				<MkA v-user-preview="inEmbedPage ? undefined : note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
 					<MkUserName :user="note.user"/>
 				</MkA>
 			</template>
@@ -42,12 +42,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 		</div>
 	</div>
 	<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
-		<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
+		<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link :preview="!inEmbedPage && !mock"/>
 		<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
 	</div>
 	<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
 		<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
-		<MkAvatar :class="$style.avatar" :user="appearNote.user" :link="!mock" :preview="!mock"/>
+		<MkAvatar :class="$style.avatar" :user="appearNote.user" :link="!mock" :preview="!inEmbedPage && !mock"/>
 		<div :class="$style.main">
 			<MkNoteHeader :note="appearNote" :mini="true"/>
 			<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
@@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 							:author="appearNote.user"
 							:nyaize="'respect'"
 							:emojiUrls="appearNote.emojis"
-							:enableEmojiMenu="true"
+							:enableEmojiMenu="!inEmbedPage"
 							:enableEmojiMenuReaction="true"
 						/>
 						<div v-if="translating || translation" :class="$style.translation">
@@ -81,8 +81,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<div v-if="appearNote.files && appearNote.files.length > 0">
 						<MkMediaList ref="galleryEl" :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/>
 					</div>
-					<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
-					<div v-if="isEnabledUrlPreview && !inEmbedPage">
+					<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :readOnly="inEmbedPage" :class="$style.poll"/>
+					<div v-if="isEnabledUrlPreview">
 						<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
 					</div>
 					<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
@@ -156,14 +156,14 @@ SPDX-License-Identifier: AGPL-3.0-only
 <div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false">
 	<I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small">
 		<template #name>
-			<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)">
+			<MkA v-user-preview="inEmbedPage ? undefined : appearNote.userId" :to="userPage(appearNote.user)">
 				<MkUserName :user="appearNote.user"/>
 			</MkA>
 		</template>
 	</I18n>
 	<I18n v-else :src="i18n.ts.userSaysSomething" tag="small">
 		<template #name>
-			<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)">
+			<MkA v-user-preview="inEmbedPage ? undefined : appearNote.userId" :to="userPage(appearNote.user)">
 				<MkUserName :user="appearNote.user"/>
 			</MkA>
 		</template>
diff --git a/packages/frontend/src/components/MkNoteEmbed.vue b/packages/frontend/src/components/MkNoteEmbed.vue
index 7a5d17520b..c8ab641385 100644
--- a/packages/frontend/src/components/MkNoteEmbed.vue
+++ b/packages/frontend/src/components/MkNoteEmbed.vue
@@ -11,12 +11,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 >
 	<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/>
 	<div v-if="isRenote" :class="$style.renote">
-		<MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/>
+		<MkAvatar :class="$style.renoteAvatar" :user="note.user" link/>
 		<i class="ti ti-repeat" style="margin-right: 4px;"></i>
 		<span :class="$style.renoteText">
 			<I18n :src="i18n.ts.renotedBy" tag="span">
 				<template #user>
-					<MkA v-user-preview="note.userId" :class="$style.renoteName" :to="userPage(note.user)">
+					<MkA :class="$style.renoteName" :to="userPage(note.user)">
 						<MkUserName :user="note.user"/>
 					</MkA>
 				</template>
@@ -36,12 +36,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 	</div>
 	<article :class="$style.note">
 		<header :class="$style.noteHeader">
-			<MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link preview/>
+			<MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link/>
 			<div :class="$style.noteHeaderBody">
 				<div :class="$style.noteHeaderBodyUpper">
 					<div style="min-width: 0;">
 						<div class="_nowrap">
-							<MkA v-user-preview="appearNote.user.id" :class="$style.noteHeaderName" :to="userPage(appearNote.user)">
+							<MkA :class="$style.noteHeaderName" :to="userPage(appearNote.user)">
 								<MkUserName :nowrap="true" :user="appearNote.user"/>
 							</MkA>
 							<span v-if="appearNote.user.isBot" :class="$style.isBot">bot</span>
@@ -72,14 +72,12 @@ SPDX-License-Identifier: AGPL-3.0-only
 					:author="appearNote.user"
 					:nyaize="'respect'"
 					:emojiUrls="appearNote.emojis"
-					:enableEmojiMenu="true"
-					:enableEmojiMenuReaction="true"
 				/>
 				<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
 				<div v-if="appearNote.files && appearNote.files.length > 0">
 					<MkMediaList :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/>
 				</div>
-				<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
+				<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :readOnly="true" :class="$style.poll"/>
 				<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
 				<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
 					<span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>
diff --git a/packages/frontend/src/components/MkNoteHeader.vue b/packages/frontend/src/components/MkNoteHeader.vue
index be5829d92f..e8ed82e2b8 100644
--- a/packages/frontend/src/components/MkNoteHeader.vue
+++ b/packages/frontend/src/components/MkNoteHeader.vue
@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	<div v-if="mock" :class="$style.name">
 		<MkUserName :user="note.user"/>
 	</div>
-	<MkA v-else v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)">
+	<MkA v-else v-user-preview="inEmbedPage ? undefined : note.user.id" :class="$style.name" :to="userPage(note.user)">
 		<MkUserName :user="note.user"/>
 	</MkA>
 	<div v-if="note.user.isBot" :class="$style.isBot">bot</div>
@@ -46,6 +46,7 @@ defineProps<{
 }>();
 
 const mock = inject<boolean>('mock', false);
+const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
 </script>
 
 <style lang="scss" module>
diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue
index c3f3c42b42..403db994cf 100644
--- a/packages/frontend/src/components/MkNoteSimple.vue
+++ b/packages/frontend/src/components/MkNoteSimple.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <template>
 <div :class="$style.root">
-	<MkAvatar :class="$style.avatar" :user="note.user" link preview/>
+	<MkAvatar :class="$style.avatar" :user="note.user" link :preview="!inEmbedPage"/>
 	<div :class="$style.main">
 		<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
 		<div>
@@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue';
+import { ref, inject } from 'vue';
 import * as Misskey from 'misskey-js';
 import MkNoteHeader from '@/components/MkNoteHeader.vue';
 import MkSubNoteContent from '@/components/MkSubNoteContent.vue';
@@ -32,6 +32,8 @@ const props = defineProps<{
 	note: Misskey.entities.Note;
 }>();
 
+const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
+
 const showContent = ref(false);
 </script>
 
diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue
index 829b37e7a7..75dce2f840 100644
--- a/packages/frontend/src/components/MkNoteSub.vue
+++ b/packages/frontend/src/components/MkNoteSub.vue
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <div v-if="!muted" :class="[$style.root, { [$style.children]: depth > 1 }]">
 	<div :class="$style.main">
 		<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
-		<MkAvatar :class="$style.avatar" :user="note.user" link preview/>
+		<MkAvatar :class="$style.avatar" :user="note.user" link :preview="!inEmbedPage"/>
 		<div :class="$style.body">
 			<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
 			<div>
@@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue';
+import { ref, inject } from 'vue';
 import * as Misskey from 'misskey-js';
 import MkNoteHeader from '@/components/MkNoteHeader.vue';
 import MkSubNoteContent from '@/components/MkSubNoteContent.vue';
@@ -62,6 +62,8 @@ const props = withDefaults(defineProps<{
 	depth: 1,
 });
 
+const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
+
 const muted = ref($i ? checkWordMute(props.note, $i, $i.mutedWords) : false);
 
 const showContent = ref(false);
diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue
index 72bd8f4f6c..917eb0819d 100644
--- a/packages/frontend/src/components/MkPoll.vue
+++ b/packages/frontend/src/components/MkPoll.vue
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<div :class="{ [$style.done]: closed || isVoted }">
+<div :class="{ [$style.done]: closed || isVoted || readOnly }">
 	<ul :class="$style.choices">
 		<li v-for="(choice, i) in poll.choices" :key="i" :class="$style.choice" @click="vote(i)">
 			<div :class="$style.bg" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div>
@@ -83,10 +83,10 @@ if (props.poll.expiresAt) {
 }
 
 const vote = async (id) => {
-	pleaseLogin(undefined, pleaseLoginContext.value);
-
 	if (props.readOnly || closed.value || isVoted.value) return;
 
+	pleaseLogin(undefined, pleaseLoginContext.value);
+
 	const { canceled } = await os.confirm({
 		type: 'question',
 		text: i18n.tsx.voteConfirm({ choice: props.poll.choices[id].text }),
@@ -145,7 +145,7 @@ const vote = async (id) => {
 
 .done {
 	.choice {
-		cursor: default;
+		cursor: initial;
 	}
 }
 </style>
diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue
index 2b26e449ca..e9d1fa9a89 100644
--- a/packages/frontend/src/components/MkSubNoteContent.vue
+++ b/packages/frontend/src/components/MkSubNoteContent.vue
@@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	</details>
 	<details v-if="note.poll">
 		<summary>{{ i18n.ts.poll }}</summary>
-		<MkPoll :noteId="note.id" :poll="note.poll"/>
+		<MkPoll :noteId="note.id" :poll="note.poll" :readOnly="inEmbedPage"/>
 	</details>
 	<button v-if="isLong && collapsed" :class="$style.fade" class="_button" @click="collapsed = false">
 		<span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span>
@@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue';
+import { ref, inject } from 'vue';
 import * as Misskey from 'misskey-js';
 import MkMediaList from '@/components/MkMediaList.vue';
 import MkPoll from '@/components/MkPoll.vue';
@@ -44,6 +44,8 @@ const props = defineProps<{
 
 const isLong = shouldCollapsed(props.note, []);
 
+const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
+
 const collapsed = ref(isLong);
 </script>
 
diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts
index 6847321d6c..0067543411 100644
--- a/packages/frontend/src/instance.ts
+++ b/packages/frontend/src/instance.ts
@@ -8,6 +8,7 @@ import * as Misskey from 'misskey-js';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 import { miLocalStorage } from '@/local-storage.js';
 import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@/const.js';
+import { embedPage } from '@/config.js';
 
 // TODO: 他のタブと永続化されたstateを同期
 
@@ -36,7 +37,7 @@ export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO
 
 export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
 
-export const isEnabledUrlPreview = computed(() => instance.enableUrlPreview ?? true);
+export const isEnabledUrlPreview = computed(() => (instance.enableUrlPreview ?? true) && !embedPage);
 
 export async function fetchInstance(force = false): Promise<Misskey.entities.MetaDetailed> {
 	if (!force) {
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index 768aa269eb..984a2fb0b1 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -172,22 +172,11 @@ type EmitsExtractor<T> = {
 	[K in keyof T as K extends `onVnode${string}` ? never : K extends `on${infer E}` ? Uncapitalize<E> : K extends string ? never : K]: T[K];
 };
 
-type PopupOptions = {
-	callEvenOnEmbedPage?: boolean;
-};
-
 export function popup<T extends Component>(
 	component: T,
 	props: ComponentProps<T>,
 	events: ComponentEmit<T> = {} as ComponentEmit<T>,
-	options: PopupOptions = {},
 ): { dispose: () => void } {
-	const _options = Object.assign({
-		callEvenOnEmbedPage: false,
-	}, options) as Required<PopupOptions>;
-
-	if (embedPage && !_options.callEvenOnEmbedPage) return { dispose: () => {} };
-
 	markRaw(component);
 
 	const id = ++popupIdCount;
diff --git a/packages/frontend/src/scripts/please-login.ts b/packages/frontend/src/scripts/please-login.ts
index 18f05bc7f4..93db66fe43 100644
--- a/packages/frontend/src/scripts/please-login.ts
+++ b/packages/frontend/src/scripts/please-login.ts
@@ -3,10 +3,11 @@
  * SPDX-License-Identifier: AGPL-3.0-only
  */
 
-import { defineAsyncComponent } from 'vue';
+import { defineAsyncComponent, inject } from 'vue';
 import { $i } from '@/account.js';
 import { i18n } from '@/i18n.js';
 import { popup } from '@/os.js';
+import { embedPage } from '@/config.js';
 
 export type OpenOnRemoteOptions = {
 	/**
@@ -47,18 +48,22 @@ export type OpenOnRemoteOptions = {
 export function pleaseLogin(path?: string, openOnRemote?: OpenOnRemoteOptions) {
 	if ($i) return;
 
-	const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
-		autoSet: true,
-		message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired,
-		openOnRemote,
-	}, {
-		cancelled: () => {
-			if (path) {
-				window.location.href = path;
-			}
-		},
-		closed: () => dispose(),
-	});
+	if (embedPage) {
+		window.open(path ?? '/', '_blank', 'noopener');
+	} else {
+		const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
+			autoSet: true,
+			message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired,
+			openOnRemote,
+		}, {
+			cancelled: () => {
+				if (path) {
+					window.location.href = path;
+				}
+			},
+			closed: () => dispose(),
+		});
+	}
 
 	throw new Error('signin required');
 }