diff --git a/src/knot/modules/geoip/geoip.c b/src/knot/modules/geoip/geoip.c
index 2f90295b4..c69907535 100644
--- a/src/knot/modules/geoip/geoip.c
+++ b/src/knot/modules/geoip/geoip.c
@@ -27,6 +27,7 @@
 #include "contrib/sockaddr.h"
 #include "contrib/string.h"
 #include "contrib/strtonum.h"
+#include "libdnssec/random.h"
 #include "libzscanner/scanner.h"
 
 #define MOD_CONFIG_FILE	"\x0B""config-file"
@@ -37,18 +38,21 @@
 
 enum operation_mode {
 	MODE_SUBNET,
-	MODE_GEODB
+	MODE_GEODB,
+	MODE_WEIGHTED
 };
 
 static const knot_lookup_t modes[] = {
-	{ MODE_SUBNET, "subnet" },
-	{ MODE_GEODB,  "geodb" },
+	{ MODE_SUBNET,   "subnet" },
+	{ MODE_GEODB,    "geodb" },
+	{ MODE_WEIGHTED, "weighted" },
 	{ 0, NULL }
 };
 
 static const char* mode_key[] = {
-	[MODE_SUBNET] = "net",
-	[MODE_GEODB]  = "geo"
+	[MODE_SUBNET]   = "net",
+	[MODE_GEODB]    = "geo",
+	[MODE_WEIGHTED] = "weight"
 };
 
 const yp_item_t geoip_conf[] = {
@@ -101,6 +105,8 @@ typedef struct {
 	uint32_t geodata_len[GEODB_MAX_DEPTH];
 	uint8_t geodepth;
 
+	uint8_t weight;
+
 	size_t count, avail;
 	knot_rrset_t *rrsets;
 	knot_rrset_t *rrsigs;
@@ -260,7 +266,7 @@ static int parse_view(knotd_mod_t *mod, geoip_ctx_t *ctx, yp_parser_t *yp, geo_v
 		return KNOT_EINVAL;
 	}
 
-	// Parse geodata/subnet.
+	// Parse geodata/subnet/weight.
 	if (ctx->mode == MODE_GEODB) {
 		if (parse_geodb_data((char *)yp->data, view->geodata, view->geodata_len,
 			&view->geodepth, ctx->paths, ctx->path_count) != 0) {
@@ -314,6 +320,13 @@ static int parse_view(knotd_mod_t *mod, geoip_ctx_t *ctx, yp_parser_t *yp, geo_v
 				              yp->line_count);
 			}
 		}
+	} else if (ctx->mode == MODE_WEIGHTED) {
+		ret = str_to_u8(yp->data, &view->weight);
+		if (ret != KNOT_EOK) {
+			knotd_mod_log(mod, LOG_ERR, "invalid weight (%s) on line %zu",
+							yp->data, yp->line_count);
+			return ret;
+		}
 	}
 
 	return KNOT_EOK;
@@ -618,6 +631,31 @@ static knotd_in_state_t geoip_process(knotd_in_state_t state, knot_pkt_t *pkt,
 				}
 			}
 		}
+	} else if (ctx->mode == MODE_WEIGHTED) {
+		uint32_t total_w = 0;
+		for (int i = 0; i < data->count; i++) {
+			geo_view_t *view = &data->views[i];
+			total_w += view->weight;
+		}
+		uint32_t r = dnssec_random_uint32_t() % total_w;
+		for (int i = 0; i < data->count; i++) {
+			geo_view_t *view = &data->views[i];
+			if (r < view->weight) {
+				for (int j = 0; j < view->count; j++) {
+					if (view->rrsets[j].type == qtype) {
+						rr = &view->rrsets[j];
+						rrsig = (view->rrsigs) ? &view->rrsigs[j] : NULL;
+						break;
+					} else if (view->rrsets[j].type == KNOT_RRTYPE_CNAME) {
+						cname = &view->rrsets[j];
+						cnamesig = (view->rrsigs) ? &view->rrsigs[j] : NULL;
+					}
+				}
+				break;
+			} else {
+				r -= view->weight;
+			}
+		}
 	}
 
 	// Return CNAME if only CNAME is found.
