diff --git a/src/main.rs b/src/main.rs
index c1d2081..480f9ca 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -146,7 +146,7 @@ enum Command {
         #[arg(long)]
         until: Option<String>,
 
-        /// JSON array of metric names to include
+        /// JSON array or comma-separated list of metric names to include
         ///
         /// Available metrics: requests, requests_per_minute, bytes_received,
         /// bytes_sent, client_errors, server_errors, error_rate,
@@ -161,7 +161,7 @@ enum Command {
         #[arg(long)]
         interval: Option<String>,
 
-        /// JSON array of field names to group by (in addition to time interval)
+        /// JSON array or comma-separated list of field names to group by (in addition to time interval)
         ///
         /// Available fields: env, consumer_id, method, path, status_code.
         #[arg(long)]
@@ -213,7 +213,7 @@ enum Command {
         #[arg(long)]
         until: Option<String>,
 
-        /// JSON array of field names to include
+        /// JSON array or comma-separated list of field names to include
         ///
         /// Available fields: timestamp, request_uuid, env, method, path,
         /// url, consumer_id, request_headers, request_size_bytes, request_body_json,
diff --git a/src/metrics.rs b/src/metrics.rs
index f74d9fd..f7c6507 100644
--- a/src/metrics.rs
+++ b/src/metrics.rs
@@ -6,7 +6,7 @@ use duckdb::arrow::ipc::reader::StreamReader;
 use duckdb::vtab::arrow::{ArrowVTab, arrow_recordbatch_to_query_params};
 
 use crate::auth::{resolve_api_base_url, resolve_api_key};
-use crate::utils::{api_post, input_err, open_db, resolve_relative_datetime};
+use crate::utils::{api_post, input_err, open_db, parse_string_list, resolve_relative_datetime};
 
 pub(crate) fn ensure_metrics_table(conn: &duckdb::Connection) -> Result<()> {
     conn.execute_batch(
@@ -55,13 +55,11 @@ pub fn run(
     let since = resolve_relative_datetime(since);
     let until = until.map(resolve_relative_datetime);
 
-    let metrics_value: serde_json::Value = serde_json::from_str(metrics)
-        .map_err(|e| input_err(format!("invalid JSON for --metrics: {e}")))?;
     let format = if db.is_some() { "arrow" } else { "ndjson" };
     let mut body = serde_json::json!({
         "format": format,
         "since": since,
-        "metrics": metrics_value,
+        "metrics": parse_string_list(metrics).map_err(|e| input_err(format!("invalid JSON for --metrics: {e}")))?,
     });
     if let Some(ref until) = until {
         body["until"] = serde_json::json!(until);
@@ -70,9 +68,8 @@ pub fn run(
         body["interval"] = serde_json::json!(interval);
     }
     if let Some(group_by) = group_by {
-        let group_by_value: serde_json::Value = serde_json::from_str(group_by)
+        body["group_by"] = parse_string_list(group_by)
             .map_err(|e| input_err(format!("invalid JSON for --group-by: {e}")))?;
-        body["group_by"] = group_by_value;
     }
     if let Some(filters) = filters {
         let filters_value: serde_json::Value = serde_json::from_str(filters)
diff --git a/src/request_logs.rs b/src/request_logs.rs
index ae5dcac..a817c15 100644
--- a/src/request_logs.rs
+++ b/src/request_logs.rs
@@ -6,7 +6,7 @@ use duckdb::arrow::ipc::reader::StreamReader;
 use duckdb::vtab::arrow::{ArrowVTab, arrow_recordbatch_to_query_params};
 
 use crate::auth::{resolve_api_base_url, resolve_api_key};
-use crate::utils::{api_post, input_err, open_db, resolve_relative_datetime};
+use crate::utils::{api_post, input_err, open_db, parse_string_list, resolve_relative_datetime};
 
 pub(crate) fn ensure_request_logs_table(conn: &duckdb::Connection) -> Result<()> {
     conn.execute_batch(
@@ -69,9 +69,8 @@ pub fn run(
         body["until"] = serde_json::json!(until);
     }
     if let Some(fields) = fields {
-        let fields_value: serde_json::Value = serde_json::from_str(fields)
+        body["fields"] = parse_string_list(fields)
             .map_err(|e| input_err(format!("invalid JSON for --fields: {e}")))?;
-        body["fields"] = fields_value;
     }
     if let Some(filters) = filters {
         let filters_value: serde_json::Value = serde_json::from_str(filters)
diff --git a/src/utils.rs b/src/utils.rs
index d8cfc34..0e74363 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -96,6 +96,20 @@ pub fn resolve_relative_datetime(s: &str) -> String {
     dt.to_rfc3339()
 }
 
+/// Parses a string as either a JSON array or a comma-separated list of strings.
+pub fn parse_string_list(s: &str) -> Result<serde_json::Value> {
+    let s = s.trim_start();
+    if s.starts_with('[') {
+        return serde_json::from_str::<serde_json::Value>(s).map_err(Into::into);
+    }
+    let items: Vec<&str> = s
+        .split(',')
+        .map(|item| item.trim())
+        .filter(|item| !item.is_empty())
+        .collect();
+    Ok(serde_json::json!(items))
+}
+
 pub fn api_get(url: &str, api_key: &str, query: &[(&str, &str)]) -> Result<Response<Body>> {
     let mut req = ureq::get(url)
         .header("Api-Key", api_key)
@@ -185,6 +199,31 @@ mod tests {
         assert_approximately_now_minus(&resolve_relative_datetime("1w"), 604_800);
     }
 
+    #[test]
+    fn test_parse_string_list() {
+        assert_eq!(
+            parse_string_list(r#"["requests","error_rate"]"#).unwrap(),
+            serde_json::json!(["requests", "error_rate"])
+        );
+        assert_eq!(
+            parse_string_list("requests,error_rate").unwrap(),
+            serde_json::json!(["requests", "error_rate"])
+        );
+        assert_eq!(
+            parse_string_list("requests").unwrap(),
+            serde_json::json!(["requests"])
+        );
+        assert_eq!(
+            parse_string_list("requests , error_rate").unwrap(),
+            serde_json::json!(["requests", "error_rate"])
+        );
+        assert_eq!(
+            parse_string_list("requests,,error_rate").unwrap(),
+            serde_json::json!(["requests", "error_rate"])
+        );
+        assert!(parse_string_list("[foo]").is_err());
+    }
+
     #[test]
     fn test_check_response() {
         assert!(check_response(&mut resp(200)).is_ok());
