diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 0f786a6b14..31b02821bf 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -756,6 +756,7 @@ high: "高"
 middle: "中"
 low: "低"
 emailNotConfiguredWarning: "メールアドレスの設定がされていません。"
+ratio: "比率"
 
 _forgotPassword:
   enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。"
diff --git a/migration/1620364649428-ad2.ts b/migration/1620364649428-ad2.ts
new file mode 100644
index 0000000000..a2d7f563c2
--- /dev/null
+++ b/migration/1620364649428-ad2.ts
@@ -0,0 +1,14 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class ad21620364649428 implements MigrationInterface {
+    name = 'ad21620364649428'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`ALTER TABLE "ad" ADD "ratio" integer NOT NULL DEFAULT '1'`);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "ratio"`);
+    }
+
+}
diff --git a/src/client/components/global/ad.vue b/src/client/components/global/ad.vue
index f88a1d2026..e340f846ee 100644
--- a/src/client/components/global/ad.vue
+++ b/src/client/components/global/ad.vue
@@ -19,7 +19,7 @@
 
 <script lang="ts">
 import { defineComponent, ref } from 'vue';
-import { instance } from '@client/instance';
+import { Instance, instance } from '@client/instance';
 import { host } from '@client/config';
 import MkButton from '@client/components/ui/button.vue';
 
@@ -45,32 +45,45 @@ export default defineComponent({
 			showMenu.value = !showMenu.value;
 		};
 
-		let ad = null;
+		const choseAd = (): Instance['ads'][number] | null => {
+			if (props.specify) {
+				return props.specify as Instance['ads'][number];
+			}
 
-		if (props.specify) {
-			ad = props.specify;
-		} else {
 			let ads = instance.ads.filter(ad => props.prefer.includes(ad.place));
 
 			if (ads.length === 0) {
 				ads = instance.ads.filter(ad => ad.place === 'square');
 			}
 
-			const high = ads.filter(ad => ad.priority === 'high');
-			const middle = ads.filter(ad => ad.priority === 'middle');
-			const low = ads.filter(ad => ad.priority === 'low');
+			const lowPriorityAds = ads.filter(ad => ad.ratio === 0);
+			ads = ads.filter(ad => ad.ratio !== 0);
 
-			if (high.length > 0) {
-				ad = high[Math.floor(Math.random() * high.length)];
-			} else if (middle.length > 0) {
-				ad = middle[Math.floor(Math.random() * middle.length)];
-			} else if (low.length > 0) {
-				ad = low[Math.floor(Math.random() * low.length)];
+			if (ads.length === 0) {
+				if (lowPriorityAds.length !== 0) {
+					return lowPriorityAds[Math.floor(Math.random() * lowPriorityAds.length)];
+				} else {
+					return null;
+				}
 			}
-		}
+
+			const totalFactor = ads.reduce((a, b) => a + b.ratio, 0);
+			const r = Math.random() * totalFactor;
+
+			let stackedFactor = 0;
+			for (const ad of ads) {
+				if (r >= stackedFactor && r <= stackedFactor + ad.ratio) {
+					return ad;
+				} else {
+					stackedFactor += ad.ratio;
+				}
+			}
+
+			return null;
+		};
 
 		return {
-			ad,
+			ad: choseAd(),
 			showMenu,
 			toggleMenu,
 			host,
diff --git a/src/client/instance.ts b/src/client/instance.ts
index bd6b1bd571..ad9e1a95fd 100644
--- a/src/client/instance.ts
+++ b/src/client/instance.ts
@@ -3,10 +3,16 @@ import { api } from './os';
 
 // TODO: 他のタブと永続化されたstateを同期
 
-type Instance = {
+export type Instance = {
 	emojis: {
 		category: string;
 	}[];
+	ads: {
+		ratio: number;
+		place: string;
+		url: string;
+		imageUrl: string;
+	}[];
 };
 
 const data = localStorage.getItem('instance');
diff --git a/src/client/pages/instance/ads.vue b/src/client/pages/instance/ads.vue
index 20747d6f9c..6b536793b7 100644
--- a/src/client/pages/instance/ads.vue
+++ b/src/client/pages/instance/ads.vue
@@ -15,12 +15,17 @@
 				<MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio>
 				<MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio>
 			</div>
+			<!--
 			<div style="margin: 32px 0;">
 				{{ $ts.priority }}
 				<MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio>
 				<MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio>
 				<MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio>
 			</div>
+			-->
+			<MkInput v-model:value="ad.ratio" type="number">
+				<span>{{ $ts.ratio }}</span>
+			</MkInput>
 			<MkInput v-model:value="ad.expiresAt" type="date">
 				<span>{{ $ts.expiration }}</span>
 			</MkInput>
@@ -82,6 +87,7 @@ export default defineComponent({
 				memo: '',
 				place: 'square',
 				priority: 'middle',
+				ratio: 1,
 				url: '',
 				imageUrl: null,
 				expiresAt: null,
diff --git a/src/models/entities/ad.ts b/src/models/entities/ad.ts
index 3279de29ea..b2fc04c4f0 100644
--- a/src/models/entities/ad.ts
+++ b/src/models/entities/ad.ts
@@ -23,11 +23,17 @@ export class Ad {
 	})
 	public place: string;
 
+	// 今は使われていないが将来的に活用される可能性はある
 	@Column('varchar', {
 		length: 32, nullable: false
 	})
 	public priority: string;
 
+	@Column('integer', {
+		default: 1, nullable: false
+	})
+	public ratio: number;
+
 	@Column('varchar', {
 		length: 1024, nullable: false
 	})
diff --git a/src/server/api/endpoints/admin/ad/create.ts b/src/server/api/endpoints/admin/ad/create.ts
index 7777e95e6e..337114a3fa 100644
--- a/src/server/api/endpoints/admin/ad/create.ts
+++ b/src/server/api/endpoints/admin/ad/create.ts
@@ -22,6 +22,9 @@ export const meta = {
 		priority: {
 			validator: $.str
 		},
+		ratio: {
+			validator: $.num.int().min(0)
+		},
 		expiresAt: {
 			validator: $.num.int()
 		},
@@ -39,6 +42,7 @@ export default define(meta, async (ps) => {
 		url: ps.url,
 		imageUrl: ps.imageUrl,
 		priority: ps.priority,
+		ratio: ps.ratio,
 		place: ps.place,
 		memo: ps.memo,
 	});
diff --git a/src/server/api/endpoints/admin/ad/update.ts b/src/server/api/endpoints/admin/ad/update.ts
index 694af98394..71e6054a88 100644
--- a/src/server/api/endpoints/admin/ad/update.ts
+++ b/src/server/api/endpoints/admin/ad/update.ts
@@ -29,6 +29,9 @@ export const meta = {
 		priority: {
 			validator: $.str
 		},
+		ratio: {
+			validator: $.num.int().min(0)
+		},
 		expiresAt: {
 			validator: $.num.int()
 		},
@@ -52,6 +55,7 @@ export default define(meta, async (ps, me) => {
 		url: ps.url,
 		place: ps.place,
 		priority: ps.priority,
+		ratio: ps.ratio,
 		memo: ps.memo,
 		imageUrl: ps.imageUrl,
 		expiresAt: new Date(ps.expiresAt),
diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts
index 5b7292ef16..d170317f1c 100644
--- a/src/server/api/endpoints/meta.ts
+++ b/src/server/api/endpoints/meta.ts
@@ -511,7 +511,7 @@ export default define(meta, async (ps, me) => {
 		ads: ads.map(ad => ({
 			url: ad.url,
 			place: ad.place,
-			priority: ad.priority,
+			ratio: ad.ratio,
 			imageUrl: ad.imageUrl,
 		})),
 		enableEmail: instance.enableEmail,