diff --git a/Cargo.lock b/Cargo.lock
index 3acfc1b..84de321 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -384,6 +384,7 @@ dependencies = [
  "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1003,7 +1004,7 @@ dependencies = [
 
 [[package]]
 name = "rand"
-version = "0.7.0"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1410,7 +1411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
  "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1892,7 +1893,7 @@ dependencies = [
 "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
 "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
-"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
+"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
 "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
 "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
diff --git a/Cargo.toml b/Cargo.toml
index e4c7b17..fccfc68 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@ reqwest = "0.9.20"
 git2 = {version = "0.10.1", features = ["https"]}
 tempfile = "3.1.0"
 dialoguer = "0.4.0"
+rand = "0.7.2"
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2.62"
diff --git a/src/extension/mod.rs b/src/extension/mod.rs
index 26da4cd..4c0f11e 100644
--- a/src/extension/mod.rs
+++ b/src/extension/mod.rs
@@ -22,6 +22,7 @@ use serde_yaml::Mapping;
 mod date;
 mod shell;
 mod script;
+mod random;
 
 pub trait Extension {
     fn name(&self) -> String;
@@ -33,5 +34,6 @@ pub fn get_extensions() -> Vec<Box<dyn Extension>> {
         Box::new(date::DateExtension::new()),
         Box::new(shell::ShellExtension::new()),
         Box::new(script::ScriptExtension::new()),
+        Box::new(random::RandomExtension::new()),
     ]
 }
\ No newline at end of file
diff --git a/src/extension/random.rs b/src/extension/random.rs
new file mode 100644
index 0000000..e44a2e6
--- /dev/null
+++ b/src/extension/random.rs
@@ -0,0 +1,93 @@
+/*
+ * This file is part of espanso.
+ *
+ * Copyright (C) 2019 Federico Terzi
+ *
+ * espanso is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * espanso is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use serde_yaml::{Mapping, Value};
+use rand::seq::SliceRandom;
+use log::{warn, error};
+
+pub struct RandomExtension {}
+
+impl RandomExtension {
+    pub fn new() -> RandomExtension {
+        RandomExtension{}
+    }
+}
+
+impl super::Extension for RandomExtension {
+    fn name(&self) -> String {
+        String::from("random")
+    }
+
+    fn calculate(&self, params: &Mapping) -> Option<String> {
+        let choices = params.get(&Value::from("choices"));
+        if choices.is_none() {
+            warn!("No 'choices' parameter specified for random variable");
+            return None
+        }
+        let choices = choices.unwrap().as_sequence();
+        if let Some(choices) = choices {
+            let str_choices = choices.iter().map(|arg| {
+                arg.as_str().unwrap_or_default().to_string()
+            }).collect::<Vec<String>>();
+
+            // Select a random choice between the possibilities
+            let choice = str_choices.choose(&mut rand::thread_rng());
+
+            match choice {
+                Some(output) => {
+                    return Some(output.clone())
+                },
+                None => {
+                    error!("Could not select a random choice.");
+                    return None
+                },
+            }
+
+        }
+
+        error!("choices array have an invalid format '{:?}'", choices);
+        None
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::extension::Extension;
+
+    #[test]
+    fn test_random_basic() {
+        let mut params = Mapping::new();
+        let choices = vec!(
+            "first",
+            "second",
+            "third",
+        );
+        params.insert(Value::from("choices"), Value::from(choices.clone()));
+
+        let extension = RandomExtension::new();
+        let output = extension.calculate(&params);
+
+        assert!(output.is_some());
+
+        let output = output.unwrap();
+
+        assert!(choices.iter().any(|x| x == &output));
+    }
+}
\ No newline at end of file