diff --git a/src-tauri/src/cmd.rs b/src-tauri/src/cmd.rs
index 5c2cb387aa020d1986307903aeb4c3be47ed48a5..e976d403d38881b45858b3163429c53a33efc422 100644
--- a/src-tauri/src/cmd.rs
+++ b/src-tauri/src/cmd.rs
@@ -1,7 +1,10 @@
 use crate::{
+  config::{read_profiles, save_profiles, ProfileItem},
   events::{emit::ClashInfoPayload, state::ClashInfoState},
-  utils::{clash, import},
+  utils::{app_home_dir, clash, fetch::fetch_profile},
 };
+use std::fs::File;
+use std::io::Write;
 use tauri::{api::process::kill_children, AppHandle, State};
 
 #[tauri::command]
@@ -14,14 +17,6 @@ pub fn restart_sidebar(app_handle: AppHandle, clash_info: State<'_, ClashInfoSta
   }
 }
 
-#[tauri::command]
-pub async fn import_profile(url: String) -> Result<String, String> {
-  match import::import_profile(&url).await {
-    Ok(_) => Ok(String::from("success")),
-    Err(_) => Err(String::from("error")),
-  }
-}
-
 #[tauri::command]
 pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option<ClashInfoPayload> {
   match clash_info.0.lock() {
@@ -29,3 +24,44 @@ pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option<ClashInfo
     _ => None,
   }
 }
+
+/// Import the Profile from url and
+/// save to the `profiles.yaml` file
+#[tauri::command]
+pub async fn import_profile(url: String) -> Result<String, String> {
+  let result = match fetch_profile(&url).await {
+    Some(r) => r,
+    None => {
+      log::error!("failed to fetch profile from `{}`", url);
+      return Err(format!("failed"));
+    }
+  };
+
+  let path = app_home_dir().join("profiles").join(&result.file);
+  File::create(path)
+    .unwrap()
+    .write(result.data.as_bytes())
+    .unwrap();
+
+  // update profiles.yaml
+  let mut profiles = read_profiles();
+  let mut items = match profiles.items {
+    Some(p) => p,
+    None => vec![],
+  };
+
+  let profile = ProfileItem {
+    name: Some(result.name),
+    file: Some(result.file),
+    mode: Some(format!("rule")),
+    url: Some(url),
+    selected: Some(vec![]), // Todo: parse the selected list
+    extra: Some(result.extra),
+  };
+
+  items.push(profile);
+  profiles.items = Some(items);
+  save_profiles(&profiles);
+
+  Ok(format!("success"))
+}
diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs
index 7a13f5aa8fed18d06a80f7a41a261b2f61c9b56c..65df3d1987e3281ceab7a7b27b2a472dc97775f6 100644
--- a/src-tauri/src/config/profiles.rs
+++ b/src-tauri/src/config/profiles.rs
@@ -39,3 +39,12 @@ pub struct ProfileExtra {
   pub total: u64,
   pub expire: u64,
 }
+
+#[derive(Default, Debug, Clone, Deserialize, Serialize)]
+/// the result from url
+pub struct ProfileResponse {
+  pub name: String,
+  pub file: String,
+  pub data: String,
+  pub extra: ProfileExtra,
+}
diff --git a/src-tauri/src/utils/import.rs b/src-tauri/src/utils/fetch.rs
similarity index 50%
rename from src-tauri/src/utils/import.rs
rename to src-tauri/src/utils/fetch.rs
index 19311f5fcc628fce9583efe4539762f6370b6771..fc58e23828c7300d04a7ad4951241afc3a30d410 100644
--- a/src-tauri/src/utils/import.rs
+++ b/src-tauri/src/utils/fetch.rs
@@ -1,9 +1,4 @@
-extern crate reqwest;
-
-use crate::config::{read_profiles, save_profiles, ProfileExtra, ProfileItem};
-use crate::utils::app_home_dir;
-use std::fs::File;
-use std::io::Write;
+use crate::config::{ProfileExtra, ProfileResponse};
 use std::time::{SystemTime, UNIX_EPOCH};
 
 /// parse the string
@@ -21,12 +16,13 @@ fn parse_string<'a>(target: &'a str, key: &'a str) -> Option<&'a str> {
   }
 }
 
-/// Todo: log
-/// Import the Profile from url
-/// save to the `verge.yaml` file
-pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> {
-  let resp = reqwest::get(profile_url).await?;
-  let header = resp.headers().clone();
+/// fetch and parse the profile
+pub async fn fetch_profile(url: &str) -> Option<ProfileResponse> {
+  let resp = match reqwest::get(url).await {
+    Ok(res) => res,
+    Err(_) => return None,
+  };
+  let header = resp.headers();
 
   // parse the Subscription Userinfo
   let extra = {
@@ -56,60 +52,34 @@ pub async fn import_profile(profile_url: &str) -> Result<(), reqwest::Error> {
     }
   };
 
-  // parse the file name
-  let file_name = {
-    let file_name = header.get("Content-Disposition").unwrap().to_str().unwrap();
-    let file_name = parse_string(file_name, "filename=");
-
-    match file_name {
-      Some(f) => f.to_string(),
-      None => {
-        let cur_time = SystemTime::now()
-          .duration_since(UNIX_EPOCH)
-          .unwrap()
-          .as_secs();
-        format!("{}.yaml", cur_time)
-      }
+  // parse the `name` and `file`
+  let (name, file) = {
+    let now = SystemTime::now()
+      .duration_since(UNIX_EPOCH)
+      .unwrap()
+      .as_secs();
+    let file = format!("{}.yaml", now);
+    let name = header.get("Content-Disposition").unwrap().to_str().unwrap();
+    let name = parse_string(name, "filename=");
+
+    match name {
+      Some(f) => (f.to_string(), file),
+      None => (file.clone(), file),
     }
   };
 
-  // save file
-  let file_data = resp.text_with_charset("utf-8").await?;
-  let file_path = app_home_dir().join("profiles").join(&file_name);
-  File::create(file_path)
-    .unwrap()
-    .write(file_data.as_bytes())
-    .unwrap();
-
-  // update profiles.yaml
-  let mut profiles = read_profiles();
-  let mut items = match profiles.items {
-    Some(p) => p,
-    None => vec![],
-  };
-
-  let profile = ProfileItem {
-    name: Some(file_name.clone()),
-    file: Some(file_name.clone()),
-    mode: Some(String::from("rule")),
-    url: Some(String::from(profile_url)),
-    selected: Some(vec![]),
-    extra: Some(extra),
-  };
-
-  let target_index = items
-    .iter()
-    .position(|x| x.name.is_some() && x.name.as_ref().unwrap().as_str() == file_name.as_str());
-
-  match target_index {
-    Some(idx) => items[idx] = profile,
-    None => items.push(profile),
+  // get the data
+  let data = match resp.text_with_charset("utf-8").await {
+    Ok(d) => d,
+    Err(_) => return None,
   };
 
-  profiles.items = Some(items);
-  save_profiles(&profiles);
-
-  Ok(())
+  Some(ProfileResponse {
+    file,
+    name,
+    data,
+    extra,
+  })
 }
 
 #[test]
diff --git a/src-tauri/src/utils/mod.rs b/src-tauri/src/utils/mod.rs
index 064253fb15a63c0c9010a7fd457441ecc8111245..047d7c938859443fc2bef4e07cdf67ab4008cfc2 100644
--- a/src-tauri/src/utils/mod.rs
+++ b/src-tauri/src/utils/mod.rs
@@ -2,6 +2,6 @@ mod dirs;
 pub use self::dirs::*;
 
 pub mod clash;
-pub mod import;
+pub mod fetch;
 pub mod init;
 pub mod sysopt;