diff --git a/app/build.gradle b/app/build.gradle
index 5006f3c..1be2bf7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -35,8 +35,8 @@ android {
         applicationId "kr.co.vividnext.sodalive"
         minSdk 23
         targetSdk 34
-        versionCode 154
-        versionName "1.31.1"
+        versionCode 156
+        versionName "1.32.0"
     }
 
     buildTypes {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4d64259..6720e17 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -174,6 +174,8 @@
         <activity android:name=".audio_content.main.v2.series.origianl_audio_drama.OriginalAudioDramaContentAllActivity" />
         <activity android:name=".audio_content.main.v2.series.completed.CompletedSeriesActivity" />
 
+        <activity android:name=".search.SearchActivity" />
+
         <activity android:name=".mypage.alarm.AlarmListActivity" />
         <activity android:name=".mypage.alarm.AddAlarmActivity" />
         <activity android:name=".mypage.alarm.select_audio_content.AlarmSelectAudioContentActivity" />
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/home/AudioContentMainTabHomeFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/home/AudioContentMainTabHomeFragment.kt
index 5483dd5..146396e 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/home/AudioContentMainTabHomeFragment.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/audio_content/main/v2/home/AudioContentMainTabHomeFragment.kt
@@ -46,6 +46,7 @@ import kr.co.vividnext.sodalive.extensions.dpToPx
 import kr.co.vividnext.sodalive.live.event_banner.EventBannerAdapter
 import kr.co.vividnext.sodalive.main.MainActivity
 import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
+import kr.co.vividnext.sodalive.search.SearchActivity
 import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
 import kr.co.vividnext.sodalive.settings.notice.NoticeDetailActivity
 import kr.co.vividnext.sodalive.settings.notification.MemberRole
@@ -154,6 +155,12 @@ class AudioContentMainTabHomeFragment : BaseFragment<FragmentAudioContentMainTab
         if (SharedPreferenceManager.token.isNotBlank()) {
             binding.flSearch.visibility = View.VISIBLE
             binding.flSearch.setOnClickListener {
+                startActivity(
+                    Intent(
+                        requireContext(),
+                        SearchActivity::class.java
+                    )
+                )
             }
         } else {
             binding.flSearch.visibility = View.GONE
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
index f713617..94cf9db 100644
--- a/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
+++ b/app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt
@@ -137,6 +137,9 @@ import kr.co.vividnext.sodalive.mypage.service_center.ServiceCenterViewModel
 import kr.co.vividnext.sodalive.network.TokenAuthenticator
 import kr.co.vividnext.sodalive.report.ReportApi
 import kr.co.vividnext.sodalive.report.ReportRepository
+import kr.co.vividnext.sodalive.search.SearchApi
+import kr.co.vividnext.sodalive.search.SearchRepository
+import kr.co.vividnext.sodalive.search.SearchViewModel
 import kr.co.vividnext.sodalive.settings.ContentSettingsViewModel
 import kr.co.vividnext.sodalive.settings.SettingsViewModel
 import kr.co.vividnext.sodalive.settings.event.EventApi
@@ -229,6 +232,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
         single { ApiBuilder().build(get(), PlaylistApi::class.java) }
         single { ApiBuilder().build(get(), AuditionApi::class.java) }
         single { ApiBuilder().build(get(), AdTrackingApi::class.java) }
+        single { ApiBuilder().build(get(), SearchApi::class.java) }
     }
 
     private val viewModelModule = module {
@@ -323,6 +327,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
         viewModel { IntroduceCreatorViewModel(get()) }
         viewModel { CompletedSeriesViewModel(get()) }
         viewModel { AlarmContentAllViewModel(get()) }
+        viewModel { SearchViewModel(get()) }
     }
 
     private val repositoryModule = module {
@@ -363,6 +368,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
         factory { AudioContentMainTabFreeRepository(get()) }
         factory { OriginalAudioDramaContentAllRepository(get()) }
         factory { AdTrackingRepository(get()) }
+        factory { SearchRepository(get()) }
     }
 
     private val moduleList = listOf(
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/search/SearchActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchActivity.kt
new file mode 100644
index 0000000..d6369b2
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchActivity.kt
@@ -0,0 +1,556 @@
+package kr.co.vividnext.sodalive.search
+
+import android.annotation.SuppressLint
+import android.app.Service
+import android.content.Intent
+import android.graphics.Rect
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.Toast
+import androidx.annotation.OptIn
+import androidx.media3.common.util.UnstableApi
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.tabs.TabLayout
+import com.jakewharton.rxbinding4.widget.textChanges
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.schedulers.Schedulers
+import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
+import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
+import kr.co.vividnext.sodalive.base.BaseActivity
+import kr.co.vividnext.sodalive.common.Constants
+import kr.co.vividnext.sodalive.common.LoadingDialog
+import kr.co.vividnext.sodalive.databinding.ActivitySearchBinding
+import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
+import kr.co.vividnext.sodalive.extensions.dpToPx
+import org.koin.android.ext.android.inject
+import java.util.concurrent.TimeUnit
+
+class SearchActivity : BaseActivity<ActivitySearchBinding>(ActivitySearchBinding::inflate) {
+
+    private val viewModel: SearchViewModel by inject()
+
+    private lateinit var imm: InputMethodManager
+    private lateinit var loadingDialog: LoadingDialog
+
+    private val handler = Handler(Looper.getMainLooper())
+
+    private lateinit var unifiedChannelAdapter: SearchAdapter
+    private lateinit var unifiedContentAdapter: SearchAdapter
+    private lateinit var unifiedSeriesAdapter: SearchAdapter
+
+    private lateinit var channelAdapter: SearchAdapter
+    private lateinit var contentAdapter: SearchAdapter
+    private lateinit var seriesAdapter: SearchAdapter
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        imm = getSystemService(
+            Service.INPUT_METHOD_SERVICE
+        ) as InputMethodManager
+
+        binding.etSearch.requestFocus()
+        handler.postDelayed({
+            val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
+            imm.showSoftInput(binding.etSearch, InputMethodManager.SHOW_IMPLICIT)
+        }, 500)
+
+        bindData()
+    }
+
+    override fun onPause() {
+        hideKeyboard()
+        super.onPause()
+    }
+
+    override fun setupView() {
+        loadingDialog = LoadingDialog(this, layoutInflater)
+        binding.ivBack.setOnClickListener { finish() }
+
+        setupTabs()
+        setupUnifiedView()
+        setupChannelListView()
+        setupContentListView()
+        setupSeriesListView()
+    }
+
+    private fun setupChannelListView() {
+        channelAdapter = SearchAdapter { clickItem(it) }
+
+        binding.rvCreator.layoutManager = LinearLayoutManager(
+            this,
+            LinearLayoutManager.VERTICAL,
+            false
+        )
+
+        binding.rvCreator.addItemDecoration(object : RecyclerView.ItemDecoration() {
+            override fun getItemOffsets(
+                outRect: Rect,
+                view: View,
+                parent: RecyclerView,
+                state: RecyclerView.State
+            ) {
+                super.getItemOffsets(outRect, view, parent, state)
+
+                outRect.left = 13.3f.dpToPx().toInt()
+                outRect.right = 13.3f.dpToPx().toInt()
+                outRect.top = 13.3f.dpToPx().toInt()
+                outRect.bottom = 13.3f.dpToPx().toInt()
+            }
+        })
+
+        binding.rvCreator.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+                super.onScrolled(recyclerView, dx, dy)
+
+                val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
+                if (
+                    layoutManager != null &&
+                    layoutManager
+                        .findLastCompletelyVisibleItemPosition() == channelAdapter.itemCount - 1
+                ) {
+                    viewModel.searchCreatorList()
+                }
+            }
+        })
+
+        binding.rvCreator.adapter = channelAdapter
+    }
+
+    private fun setupContentListView() {
+        contentAdapter = SearchAdapter { clickItem(it) }
+
+        binding.rvContent.layoutManager = LinearLayoutManager(
+            this,
+            LinearLayoutManager.VERTICAL,
+            false
+        )
+
+        binding.rvContent.addItemDecoration(object : RecyclerView.ItemDecoration() {
+            override fun getItemOffsets(
+                outRect: Rect,
+                view: View,
+                parent: RecyclerView,
+                state: RecyclerView.State
+            ) {
+                super.getItemOffsets(outRect, view, parent, state)
+
+                outRect.left = 13.3f.dpToPx().toInt()
+                outRect.right = 13.3f.dpToPx().toInt()
+                outRect.top = 13.3f.dpToPx().toInt()
+                outRect.bottom = 13.3f.dpToPx().toInt()
+            }
+        })
+
+        binding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+                super.onScrolled(recyclerView, dx, dy)
+
+                val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
+                if (
+                    layoutManager != null &&
+                    layoutManager
+                        .findLastCompletelyVisibleItemPosition() == contentAdapter.itemCount - 1
+                ) {
+                    viewModel.searchContentList()
+                }
+            }
+        })
+
+        binding.rvContent.adapter = contentAdapter
+    }
+
+    private fun setupSeriesListView() {
+        seriesAdapter = SearchAdapter { clickItem(it) }
+
+        binding.rvSeries.layoutManager = LinearLayoutManager(
+            this,
+            LinearLayoutManager.VERTICAL,
+            false
+        )
+
+        binding.rvSeries.addItemDecoration(object : RecyclerView.ItemDecoration() {
+            override fun getItemOffsets(
+                outRect: Rect,
+                view: View,
+                parent: RecyclerView,
+                state: RecyclerView.State
+            ) {
+                super.getItemOffsets(outRect, view, parent, state)
+
+                outRect.left = 13.3f.dpToPx().toInt()
+                outRect.right = 13.3f.dpToPx().toInt()
+                outRect.top = 13.3f.dpToPx().toInt()
+                outRect.bottom = 13.3f.dpToPx().toInt()
+            }
+        })
+
+        binding.rvSeries.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+                super.onScrolled(recyclerView, dx, dy)
+
+                val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
+                if (
+                    layoutManager != null &&
+                    layoutManager
+                        .findLastCompletelyVisibleItemPosition() == seriesAdapter.itemCount - 1
+                ) {
+                    viewModel.searchSeriesList()
+                }
+            }
+        })
+
+        binding.rvSeries.adapter = seriesAdapter
+    }
+
+    private fun setupUnifiedView() {
+        unifiedChannelAdapter = SearchAdapter { clickItem(it) }
+        unifiedContentAdapter = SearchAdapter { clickItem(it) }
+        unifiedSeriesAdapter = SearchAdapter { clickItem(it) }
+
+        binding.tvMoreCreator.setOnClickListener {
+            viewModel.changeTab(SearchViewModel.SearchPageTab.CREATOR)
+        }
+
+        binding.tvMoreContent.setOnClickListener {
+            viewModel.changeTab(SearchViewModel.SearchPageTab.CONTENT)
+        }
+
+        binding.tvMoreSeries.setOnClickListener {
+            viewModel.changeTab(SearchViewModel.SearchPageTab.SERIES)
+        }
+
+        binding.rvUnifiedCreator.layoutManager = LinearLayoutManager(
+            this,
+            LinearLayoutManager.VERTICAL,
+            false
+        )
+        binding.rvUnifiedCreator.addItemDecoration(object : RecyclerView.ItemDecoration() {
+            override fun getItemOffsets(
+                outRect: Rect,
+                view: View,
+                parent: RecyclerView,
+                state: RecyclerView.State
+            ) {
+                super.getItemOffsets(outRect, view, parent, state)
+
+                outRect.left = 13.3f.dpToPx().toInt()
+                outRect.right = 13.3f.dpToPx().toInt()
+                outRect.top = 13.3f.dpToPx().toInt()
+                outRect.bottom = 13.3f.dpToPx().toInt()
+            }
+        })
+        binding.rvUnifiedCreator.adapter = unifiedChannelAdapter
+
+        binding.rvUnifiedContent.layoutManager = LinearLayoutManager(
+            this,
+            LinearLayoutManager.VERTICAL,
+            false
+        )
+        binding.rvUnifiedContent.addItemDecoration(object : RecyclerView.ItemDecoration() {
+            override fun getItemOffsets(
+                outRect: Rect,
+                view: View,
+                parent: RecyclerView,
+                state: RecyclerView.State
+            ) {
+                super.getItemOffsets(outRect, view, parent, state)
+
+                outRect.left = 13.3f.dpToPx().toInt()
+                outRect.right = 13.3f.dpToPx().toInt()
+                outRect.top = 13.3f.dpToPx().toInt()
+                outRect.bottom = 13.3f.dpToPx().toInt()
+            }
+        })
+        binding.rvUnifiedContent.adapter = unifiedContentAdapter
+
+        binding.rvUnifiedSeries.layoutManager = LinearLayoutManager(
+            this,
+            LinearLayoutManager.VERTICAL,
+            false
+        )
+        binding.rvUnifiedSeries.addItemDecoration(object : RecyclerView.ItemDecoration() {
+            override fun getItemOffsets(
+                outRect: Rect,
+                view: View,
+                parent: RecyclerView,
+                state: RecyclerView.State
+            ) {
+                super.getItemOffsets(outRect, view, parent, state)
+
+                outRect.left = 13.3f.dpToPx().toInt()
+                outRect.right = 13.3f.dpToPx().toInt()
+                outRect.top = 13.3f.dpToPx().toInt()
+                outRect.bottom = 13.3f.dpToPx().toInt()
+            }
+        })
+        binding.rvUnifiedSeries.adapter = unifiedSeriesAdapter
+    }
+
+    @OptIn(UnstableApi::class)
+    private fun clickItem(item: SearchResponseItem) {
+        hideKeyboard()
+
+        startActivity(
+            when (item.type) {
+                SearchResponseType.CREATOR -> {
+                    Intent(applicationContext, UserProfileActivity::class.java).apply {
+                        putExtra(Constants.EXTRA_USER_ID, item.id)
+                    }
+                }
+
+                SearchResponseType.CONTENT -> {
+                    Intent(applicationContext, AudioContentDetailActivity::class.java).apply {
+                        putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, item.id)
+                    }
+                }
+
+                SearchResponseType.SERIES -> {
+                    Intent(applicationContext, SeriesDetailActivity::class.java).apply {
+                        putExtra(Constants.EXTRA_SERIES_ID, item.id)
+                    }
+                }
+            }
+        )
+    }
+
+    private fun setupTabs() {
+        val tabs = binding.tabs
+        val tabTitles = listOf("통합", "채널", "콘텐츠", "시리즈")
+        for (title in tabTitles) {
+            tabs.addTab(tabs.newTab().setText(title))
+        }
+
+        tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+            override fun onTabSelected(tab: TabLayout.Tab) {
+                val selectedTab = SearchViewModel.SearchPageTab.fromOrdinal(tab.position)
+                viewModel.changeTab(selectedTab!!)
+
+                tab.view.isSelected = true
+                hideKeyboard()
+            }
+
+            override fun onTabUnselected(tab: TabLayout.Tab) {
+                tab.view.isSelected = false
+            }
+
+            override fun onTabReselected(tab: TabLayout.Tab) {
+            }
+        })
+    }
+
+    @SuppressLint("NotifyDataSetChanged")
+    private fun bindData() {
+        compositeDisposable.add(
+            binding.etSearch.textChanges().skip(1)
+                .debounce(500, TimeUnit.MILLISECONDS)
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribeOn(Schedulers.io())
+                .subscribe {
+                    channelAdapter.clear()
+                    contentAdapter.clear()
+                    seriesAdapter.clear()
+
+                    unifiedChannelAdapter.clear()
+                    unifiedContentAdapter.clear()
+                    unifiedSeriesAdapter.clear()
+
+                    viewModel.keyword = it.toString()
+                    if (it.length >= 2) {
+                        viewModel.searchUnified()
+                        binding.tabs.visibility = View.VISIBLE
+                        binding.tvResultX.visibility = View.GONE
+                    } else {
+                        binding.nsSearchUnified.visibility = View.GONE
+                        binding.rvCreator.visibility = View.GONE
+                        binding.rvContent.visibility = View.GONE
+                        binding.rvSeries.visibility = View.GONE
+                        binding.tabs.visibility = View.GONE
+                        binding.tvResultX.visibility = View.GONE
+                    }
+                }
+        )
+
+        viewModel.toastLiveData.observe(this) {
+            it?.let { Toast.makeText(this@SearchActivity, it, Toast.LENGTH_LONG).show() }
+        }
+
+        viewModel.isLoading.observe(this) {
+            if (it) {
+                loadingDialog.show(screenWidth, "")
+            } else {
+                loadingDialog.dismiss()
+            }
+        }
+
+        viewModel.searchUnifiedLiveData.observe(this) {
+            if (
+                it.creatorList.isEmpty() &&
+                it.seriesList.isEmpty() &&
+                it.contentList.isEmpty()
+            ) {
+                binding.tabs.visibility = View.GONE
+                hideAllView()
+                if (viewModel.keyword.isNotBlank()) {
+                    binding.tvResultX.visibility = View.VISIBLE
+                } else {
+                    binding.tvResultX.visibility = View.GONE
+                }
+            } else {
+                binding.tabs.visibility = View.VISIBLE
+                binding.nsSearchUnified.visibility = View.VISIBLE
+
+                if (it.creatorList.isNotEmpty()) {
+                    binding.tvCreatorTitle.visibility = View.VISIBLE
+                    binding.tvMoreCreator.visibility = View.VISIBLE
+                    binding.rvUnifiedCreator.visibility = View.VISIBLE
+                    unifiedChannelAdapter.items.addAll(it.creatorList)
+                    unifiedChannelAdapter.notifyDataSetChanged()
+                } else {
+                    binding.tvCreatorTitle.visibility = View.GONE
+                    binding.tvMoreCreator.visibility = View.GONE
+                    binding.rvUnifiedCreator.visibility = View.GONE
+                }
+
+                if (it.contentList.isNotEmpty()) {
+                    binding.tvContentTitle.visibility = View.VISIBLE
+                    binding.tvMoreContent.visibility = View.VISIBLE
+                    binding.rvUnifiedContent.visibility = View.VISIBLE
+                    unifiedContentAdapter.items.addAll(it.contentList)
+                    unifiedContentAdapter.notifyDataSetChanged()
+                } else {
+                    binding.tvContentTitle.visibility = View.GONE
+                    binding.tvMoreContent.visibility = View.GONE
+                    binding.rvUnifiedContent.visibility = View.GONE
+                }
+
+                if (it.seriesList.isNotEmpty()) {
+                    binding.tvSeriesTitle.visibility = View.VISIBLE
+                    binding.tvMoreSeries.visibility = View.VISIBLE
+                    binding.rvUnifiedSeries.visibility = View.VISIBLE
+                    unifiedSeriesAdapter.items.addAll(it.seriesList)
+                    unifiedSeriesAdapter.notifyDataSetChanged()
+                } else {
+                    binding.tvSeriesTitle.visibility = View.GONE
+                    binding.tvMoreSeries.visibility = View.GONE
+                    binding.rvUnifiedSeries.visibility = View.GONE
+                }
+            }
+        }
+
+        viewModel.searchCreatorLiveData.observe(this) {
+            channelAdapter.items.addAll(it)
+            channelAdapter.notifyDataSetChanged()
+
+            hideAllView()
+            if (channelAdapter.items.isEmpty()) {
+                if (viewModel.keyword.isNotBlank()) {
+                    binding.tvResultX.visibility = View.VISIBLE
+                } else {
+                    binding.tvResultX.visibility = View.GONE
+                }
+            } else {
+                binding.rvCreator.visibility = View.VISIBLE
+            }
+        }
+
+        viewModel.searchContentLiveData.observe(this) {
+            contentAdapter.items.addAll(it)
+            contentAdapter.notifyDataSetChanged()
+
+            hideAllView()
+            if (contentAdapter.items.isEmpty()) {
+                if (viewModel.keyword.isNotBlank()) {
+                    binding.tvResultX.visibility = View.VISIBLE
+                } else {
+                    binding.tvResultX.visibility = View.GONE
+                }
+            } else {
+                binding.rvContent.visibility = View.VISIBLE
+            }
+        }
+
+        viewModel.searchSeriesLiveData.observe(this) {
+            seriesAdapter.items.addAll(it)
+            seriesAdapter.notifyDataSetChanged()
+
+            hideAllView()
+            if (seriesAdapter.items.isEmpty()) {
+                if (viewModel.keyword.isNotBlank()) {
+                    binding.tvResultX.visibility = View.VISIBLE
+                } else {
+                    binding.tvResultX.visibility = View.GONE
+                }
+            } else {
+                binding.rvSeries.visibility = View.VISIBLE
+            }
+        }
+
+        viewModel.currentTabLiveData.observe(this) { currentTab ->
+            hideAllView()
+
+            binding.tabs.getTabAt(currentTab.ordinal)?.select()
+            when (currentTab) {
+                SearchViewModel.SearchPageTab.CREATOR -> {
+                    if (channelAdapter.items.isEmpty()) {
+                        viewModel.searchCreatorList()
+                    } else {
+                        binding.rvCreator.visibility = View.VISIBLE
+                    }
+                }
+
+                SearchViewModel.SearchPageTab.CONTENT -> {
+                    if (contentAdapter.items.isEmpty()) {
+                        viewModel.searchContentList()
+                    } else {
+                        binding.rvContent.visibility = View.VISIBLE
+                    }
+                }
+
+                SearchViewModel.SearchPageTab.SERIES -> {
+                    if (seriesAdapter.items.isEmpty()) {
+                        viewModel.searchSeriesList()
+                    } else {
+                        binding.rvSeries.visibility = View.VISIBLE
+                    }
+                }
+
+                else -> {
+                    if (
+                        unifiedChannelAdapter.items.isEmpty() &&
+                        unifiedContentAdapter.items.isEmpty() &&
+                        unifiedSeriesAdapter.items.isEmpty()
+                    ) {
+                        if (viewModel.keyword.isNotBlank()) {
+                            binding.tvResultX.visibility = View.VISIBLE
+                        } else {
+                            binding.tvResultX.visibility = View.GONE
+                        }
+                    } else {
+                        binding.nsSearchUnified.visibility = View.VISIBLE
+                    }
+                }
+            }
+        }
+    }
+
+    private fun hideAllView() {
+        binding.nsSearchUnified.visibility = View.GONE
+        binding.rvCreator.visibility = View.GONE
+        binding.rvContent.visibility = View.GONE
+        binding.rvSeries.visibility = View.GONE
+        binding.tvResultX.visibility = View.GONE
+    }
+
+    private fun hideKeyboard() {
+        handler.postDelayed({
+            imm.hideSoftInputFromWindow(
+                window.decorView.applicationWindowToken,
+                InputMethodManager.HIDE_NOT_ALWAYS
+            )
+        }, 100)
+    }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/search/SearchAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchAdapter.kt
new file mode 100644
index 0000000..2d3baae
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchAdapter.kt
@@ -0,0 +1,97 @@
+package kr.co.vividnext.sodalive.search
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import coil.load
+import coil.transform.CircleCropTransformation
+import coil.transform.RoundedCornersTransformation
+import kr.co.vividnext.sodalive.R
+import kr.co.vividnext.sodalive.databinding.ItemSearchBinding
+import kr.co.vividnext.sodalive.extensions.dpToPx
+
+class SearchAdapter(
+    private val onClickItem: (SearchResponseItem) -> Unit
+) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() {
+    inner class ViewHolder(
+        private val context: Context,
+        private val binding: ItemSearchBinding
+    ) : RecyclerView.ViewHolder(binding.root) {
+
+        @SuppressLint("CheckResult")
+        fun bind(item: SearchResponseItem) {
+            binding.ivProfile.visibility = View.GONE
+            binding.ivContent.visibility = View.GONE
+            binding.ivSeries.visibility = View.GONE
+            binding.tvNickname.visibility = View.GONE
+
+            when (item.type) {
+                SearchResponseType.CREATOR -> {
+                    binding.ivProfile.visibility = View.VISIBLE
+                    binding.ivProfile.load(item.imageUrl) {
+                        crossfade(true)
+                        placeholder(R.drawable.bg_placeholder)
+                        transformations(CircleCropTransformation())
+                    }
+                }
+
+                SearchResponseType.CONTENT -> {
+                    binding.ivContent.visibility = View.VISIBLE
+                    binding.ivContent.load(item.imageUrl) {
+                        crossfade(true)
+                        placeholder(R.drawable.bg_placeholder)
+                        transformations(RoundedCornersTransformation(5.3f.dpToPx()))
+                    }
+                    binding.tvNickname.visibility = View.VISIBLE
+                }
+
+                SearchResponseType.SERIES -> {
+                    binding.ivSeries.visibility = View.VISIBLE
+                    binding.ivSeries.load(item.imageUrl) {
+                        crossfade(true)
+                        placeholder(R.drawable.bg_placeholder)
+                        transformations(RoundedCornersTransformation(5.3f.dpToPx()))
+                    }
+
+                    binding.ivSeries.load(item.imageUrl) {
+                        crossfade(true)
+                        placeholder(R.drawable.bg_placeholder)
+                        transformations(RoundedCornersTransformation(5.3f.dpToPx()))
+                    }
+                    binding.tvNickname.visibility = View.VISIBLE
+                }
+            }
+
+            binding.tvTitle.text = item.title
+            binding.tvNickname.text = item.nickname
+
+            binding.root.setOnClickListener { onClickItem(item) }
+        }
+    }
+
+    val items: MutableList<SearchResponseItem> = mutableListOf()
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
+        parent.context,
+        ItemSearchBinding.inflate(
+            LayoutInflater.from(parent.context),
+            parent,
+            false
+        )
+    )
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        holder.bind(items[position])
+    }
+
+    override fun getItemCount() = items.size
+
+    @SuppressLint("NotifyDataSetChanged")
+    fun clear() {
+        items.clear()
+        notifyDataSetChanged()
+    }
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/search/SearchApi.kt b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchApi.kt
new file mode 100644
index 0000000..a89b77e
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchApi.kt
@@ -0,0 +1,48 @@
+package kr.co.vividnext.sodalive.search
+
+import io.reactivex.rxjava3.core.Single
+import kr.co.vividnext.sodalive.common.ApiResponse
+import kr.co.vividnext.sodalive.settings.ContentType
+import retrofit2.http.GET
+import retrofit2.http.Header
+import retrofit2.http.Query
+
+interface SearchApi {
+    @GET("/search")
+    fun searchUnified(
+        @Query("keyword") keyword: String,
+        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
+        @Query("contentType") contentType: ContentType,
+        @Header("Authorization") authHeader: String
+    ): Single<ApiResponse<SearchUnifiedResponse>>
+
+    @GET("/search/creators")
+    fun searchCreatorList(
+        @Query("keyword") keyword: String,
+        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
+        @Query("contentType") contentType: ContentType,
+        @Query("page") page: Int,
+        @Query("size") size: Int,
+        @Header("Authorization") authHeader: String
+    ): Single<ApiResponse<SearchResponse>>
+
+    @GET("/search/contents")
+    fun searchContentList(
+        @Query("keyword") keyword: String,
+        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
+        @Query("contentType") contentType: ContentType,
+        @Query("page") page: Int,
+        @Query("size") size: Int,
+        @Header("Authorization") authHeader: String
+    ): Single<ApiResponse<SearchResponse>>
+
+    @GET("/search/series")
+    fun searchSeriesList(
+        @Query("keyword") keyword: String,
+        @Query("isAdultContentVisible") isAdultContentVisible: Boolean,
+        @Query("contentType") contentType: ContentType,
+        @Query("page") page: Int,
+        @Query("size") size: Int,
+        @Header("Authorization") authHeader: String
+    ): Single<ApiResponse<SearchResponse>>
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/search/SearchRepository.kt b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchRepository.kt
new file mode 100644
index 0000000..2225897
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchRepository.kt
@@ -0,0 +1,58 @@
+package kr.co.vividnext.sodalive.search
+
+import kr.co.vividnext.sodalive.common.SharedPreferenceManager
+import kr.co.vividnext.sodalive.settings.ContentType
+
+class SearchRepository(private val api: SearchApi) {
+    fun searchUnified(
+        keyword: String,
+        token: String
+    ) = api.searchUnified(
+        keyword = keyword,
+        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
+        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
+        authHeader = token
+    )
+
+    fun searchCreatorList(
+        keyword: String,
+        page: Int,
+        size: Int,
+        token: String
+    ) = api.searchCreatorList(
+        keyword = keyword,
+        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
+        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
+        page = page - 1,
+        size = size,
+        authHeader = token
+    )
+
+    fun searchContentList(
+        keyword: String,
+        page: Int,
+        size: Int,
+        token: String
+    ) = api.searchContentList(
+        keyword = keyword,
+        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
+        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
+        page = page - 1,
+        size = size,
+        authHeader = token
+    )
+
+    fun searchSeriesList(
+        keyword: String,
+        page: Int,
+        size: Int,
+        token: String
+    ) = api.searchSeriesList(
+        keyword = keyword,
+        isAdultContentVisible = SharedPreferenceManager.isAdultContentVisible,
+        contentType = ContentType.values()[SharedPreferenceManager.contentPreference],
+        page = page - 1,
+        size = size,
+        authHeader = token
+    )
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/search/SearchResponse.kt b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchResponse.kt
new file mode 100644
index 0000000..b612ceb
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchResponse.kt
@@ -0,0 +1,33 @@
+package kr.co.vividnext.sodalive.search
+
+import androidx.annotation.Keep
+import com.google.gson.annotations.SerializedName
+
+@Keep
+data class SearchUnifiedResponse(
+    @SerializedName("creatorList") val creatorList: List<SearchResponseItem>,
+    @SerializedName("contentList") val contentList: List<SearchResponseItem>,
+    @SerializedName("seriesList") val seriesList: List<SearchResponseItem>
+)
+
+@Keep
+data class SearchResponse(
+    @SerializedName("totalCount") val totalCount: Int,
+    @SerializedName("items") val items: List<SearchResponseItem>
+)
+
+@Keep
+data class SearchResponseItem(
+    @SerializedName("id") val id: Long,
+    @SerializedName("imageUrl") val imageUrl: String,
+    @SerializedName("title") val title: String,
+    @SerializedName("nickname") val nickname: String,
+    @SerializedName("type") val type: SearchResponseType
+)
+
+@Keep
+enum class SearchResponseType {
+    @SerializedName("CREATOR") CREATOR,
+    @SerializedName("CONTENT") CONTENT,
+    @SerializedName("SERIES") SERIES
+}
diff --git a/app/src/main/java/kr/co/vividnext/sodalive/search/SearchViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchViewModel.kt
new file mode 100644
index 0000000..781516d
--- /dev/null
+++ b/app/src/main/java/kr/co/vividnext/sodalive/search/SearchViewModel.kt
@@ -0,0 +1,250 @@
+package kr.co.vividnext.sodalive.search
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import com.orhanobut.logger.Logger
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.schedulers.Schedulers
+import kr.co.vividnext.sodalive.base.BaseViewModel
+import kr.co.vividnext.sodalive.common.SharedPreferenceManager
+
+class SearchViewModel(
+    private val repository: SearchRepository
+) : BaseViewModel() {
+    enum class SearchPageTab {
+        UNIFIED, CREATOR, CONTENT, SERIES;
+
+        companion object {
+            fun fromOrdinal(ordinal: Int): SearchPageTab? {
+                return SearchPageTab.values().getOrNull(ordinal)
+            }
+        }
+    }
+
+    var keyword = ""
+
+    private val _currentTabLiveData = MutableLiveData(SearchPageTab.UNIFIED)
+    val currentTabLiveData: LiveData<SearchPageTab>
+        get() = _currentTabLiveData
+
+    private val _toastLiveData = MutableLiveData<String?>()
+    val toastLiveData: LiveData<String?>
+        get() = _toastLiveData
+
+    private var _isLoading = MutableLiveData(false)
+    val isLoading: LiveData<Boolean>
+        get() = _isLoading
+
+    private var _searchUnifiedLiveData = MutableLiveData<SearchUnifiedResponse>()
+    val searchUnifiedLiveData: LiveData<SearchUnifiedResponse>
+        get() = _searchUnifiedLiveData
+
+    private var _searchCreatorLiveData = MutableLiveData<List<SearchResponseItem>>()
+    val searchCreatorLiveData: LiveData<List<SearchResponseItem>>
+        get() = _searchCreatorLiveData
+
+    private var _searchContentLiveData = MutableLiveData<List<SearchResponseItem>>()
+    val searchContentLiveData: LiveData<List<SearchResponseItem>>
+        get() = _searchContentLiveData
+
+    private var _searchSeriesLiveData = MutableLiveData<List<SearchResponseItem>>()
+    val searchSeriesLiveData: LiveData<List<SearchResponseItem>>
+        get() = _searchSeriesLiveData
+
+    private var searchCreatorPage = 1
+    private var searchContentPage = 1
+    private var searchSeriesPage = 1
+
+    private var isSearchCreatorLast = false
+    private var isSearchContentLast = false
+    private var isSearchSeriesLast = false
+
+    private val size = 20
+
+    fun changeTab(tab: SearchPageTab) {
+        _currentTabLiveData.value = tab
+    }
+
+    fun searchUnified() {
+        if (!_isLoading.value!!) {
+            _currentTabLiveData.value = SearchPageTab.UNIFIED
+
+            searchCreatorPage = 1
+            searchContentPage = 1
+            searchSeriesPage = 1
+
+            isSearchCreatorLast = false
+            isSearchContentLast = false
+            isSearchSeriesLast = false
+
+            _isLoading.value = true
+            compositeDisposable.add(
+                repository.searchUnified(
+                    keyword = keyword,
+                    token = "Bearer ${SharedPreferenceManager.token}"
+                )
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(
+                        {
+                            _isLoading.value = false
+                            if (it.success && it.data != null) {
+                                _searchUnifiedLiveData.value = it.data!!
+                            } else {
+                                if (it.message != null) {
+                                    _toastLiveData.value = it.message
+                                } else {
+                                    _toastLiveData
+                                        .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                                }
+                            }
+                        },
+                        {
+                            _isLoading.value = false
+                            it.message?.let { message -> Logger.e(message) }
+                            _toastLiveData
+                                .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                        }
+                    )
+            )
+        }
+    }
+
+    fun searchCreatorList() {
+        if (!_isLoading.value!! && !isSearchCreatorLast) {
+            _isLoading.value = true
+            compositeDisposable.add(
+                repository.searchCreatorList(
+                    keyword = keyword,
+                    page = searchCreatorPage,
+                    size = size,
+                    token = "Bearer ${SharedPreferenceManager.token}"
+                )
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(
+                        {
+                            _isLoading.value = false
+                            if (it.success && it.data != null) {
+                                searchCreatorPage += 1
+
+                                val data = it.data
+                                _searchCreatorLiveData.value = data.items
+
+                                if (data.items.isEmpty()) {
+                                    isSearchCreatorLast = true
+                                }
+                            } else {
+                                if (it.message != null) {
+                                    _toastLiveData.value = it.message
+                                } else {
+                                    _toastLiveData
+                                        .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                                }
+                            }
+                        },
+                        {
+                            _isLoading.value = false
+                            it.message?.let { message -> Logger.e(message) }
+                            _toastLiveData
+                                .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                        }
+                    )
+            )
+        } else {
+            _searchCreatorLiveData.value = emptyList()
+        }
+    }
+
+    fun searchContentList() {
+        if (!_isLoading.value!! && !isSearchContentLast) {
+            _isLoading.value = true
+            compositeDisposable.add(
+                repository.searchContentList(
+                    keyword = keyword,
+                    page = searchContentPage,
+                    size = size,
+                    token = "Bearer ${SharedPreferenceManager.token}"
+                )
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(
+                        {
+                            _isLoading.value = false
+                            if (it.success && it.data != null) {
+                                searchContentPage += 1
+
+                                val data = it.data
+                                _searchContentLiveData.value = data.items
+
+                                if (data.items.isEmpty()) {
+                                    isSearchContentLast = true
+                                }
+                            } else {
+                                if (it.message != null) {
+                                    _toastLiveData.value = it.message
+                                } else {
+                                    _toastLiveData
+                                        .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                                }
+                            }
+                        },
+                        {
+                            _isLoading.value = false
+                            it.message?.let { message -> Logger.e(message) }
+                            _toastLiveData
+                                .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                        }
+                    )
+            )
+        } else {
+            _searchContentLiveData.value = emptyList()
+        }
+    }
+
+    fun searchSeriesList() {
+        if (!_isLoading.value!! && !isSearchSeriesLast) {
+            _isLoading.value = true
+            compositeDisposable.add(
+                repository.searchSeriesList(
+                    keyword = keyword,
+                    page = searchSeriesPage,
+                    size = size,
+                    token = "Bearer ${SharedPreferenceManager.token}"
+                )
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(
+                        {
+                            _isLoading.value = false
+                            if (it.success && it.data != null) {
+                                searchSeriesPage += 1
+
+                                val data = it.data
+                                _searchSeriesLiveData.value = data.items
+
+                                if (data.items.isEmpty()) {
+                                    isSearchSeriesLast = true
+                                }
+                            } else {
+                                if (it.message != null) {
+                                    _toastLiveData.value = it.message
+                                } else {
+                                    _toastLiveData
+                                        .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                                }
+                            }
+                        },
+                        {
+                            _isLoading.value = false
+                            it.message?.let { message -> Logger.e(message) }
+                            _toastLiveData
+                                .value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
+                        }
+                    )
+            )
+        } else {
+            _searchSeriesLiveData.value = emptyList()
+        }
+    }
+}
diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml
new file mode 100644
index 0000000..bf6b0a7
--- /dev/null
+++ b/app/src/main/res/layout/activity_search.xml
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/black"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="13.3dp"
+        android:gravity="center_vertical"
+        android:paddingTop="13.3dp">
+
+        <ImageView
+            android:id="@+id/iv_back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="@null"
+            android:padding="13.3dp"
+            android:src="@drawable/ic_back" />
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="50dp"
+            android:background="@drawable/bg_round_corner_6_7_222222_bbbbbb">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="21.3dp"
+                android:contentDescription="@null"
+                android:src="@drawable/ic_title_search_black" />
+
+            <EditText
+                android:id="@+id/et_search"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:background="@null"
+                android:fontFamily="@font/gmarket_sans_medium"
+                android:gravity="center_vertical"
+                android:hint="검색"
+                android:importantForAutofill="no"
+                android:inputType="textWebEditText"
+                android:paddingHorizontal="54.67dp"
+                android:textColor="@color/color_eeeeee"
+                android:textColorHint="@color/color_555555"
+                android:textCursorDrawable="@drawable/edit_text_cursor"
+                android:textSize="13.3sp" />
+        </RelativeLayout>
+    </LinearLayout>
+
+    <com.google.android.material.tabs.TabLayout
+        android:id="@+id/tabs"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="13.3dp"
+        android:background="@android:color/transparent"
+        android:clipToPadding="false"
+        android:elevation="0dp"
+        android:paddingHorizontal="13.3dp"
+        android:visibility="gone"
+        app:tabGravity="start"
+        app:tabIndicatorFullWidth="false"
+        app:tabIndicatorHeight="0dp"
+        app:tabMinWidth="45dp"
+        app:tabMode="scrollable"
+        app:tabPaddingBottom="15dp"
+        app:tabPaddingTop="15dp"
+        app:tabSelectedTextColor="@color/color_3bb9f1"
+        app:tabTextAppearance="@style/ContentMainTabText"
+        app:tabTextColor="@color/color_bbbbbb" />
+
+    <androidx.core.widget.NestedScrollView
+        android:id="@+id/ns_search_unified"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@+id/tv_creator_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="13.3dp"
+                android:fontFamily="@font/gmarket_sans_bold"
+                android:text="채널"
+                android:textColor="@color/color_eeeeee"
+                android:textSize="16sp" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_unified_creator"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:clipToPadding="false"
+                android:padding="13.3dp" />
+
+            <TextView
+                android:id="@+id/tv_more_creator"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="13.3dp"
+                android:layout_marginBottom="30dp"
+                android:background="@color/color_cc333333"
+                android:fontFamily="@font/gmarket_sans_medium"
+                android:gravity="center"
+                android:paddingVertical="10dp"
+                android:text="더보기 >"
+                android:textColor="@color/color_777777"
+                android:textSize="13.3sp" />
+
+            <TextView
+                android:id="@+id/tv_content_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="13.3dp"
+                android:fontFamily="@font/gmarket_sans_bold"
+                android:text="콘텐츠"
+                android:textColor="@color/color_eeeeee"
+                android:textSize="16sp" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_unified_content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:clipToPadding="false"
+                android:padding="13.3dp" />
+
+            <TextView
+                android:id="@+id/tv_more_content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="13.3dp"
+                android:layout_marginBottom="30dp"
+                android:background="@color/color_cc333333"
+                android:fontFamily="@font/gmarket_sans_medium"
+                android:gravity="center"
+                android:paddingVertical="10dp"
+                android:text="더보기 >"
+                android:textColor="@color/color_777777"
+                android:textSize="13.3sp" />
+
+            <TextView
+                android:id="@+id/tv_series_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="13.3dp"
+                android:fontFamily="@font/gmarket_sans_bold"
+                android:text="시리즈"
+                android:textColor="@color/color_eeeeee"
+                android:textSize="16sp" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_unified_series"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:clipToPadding="false"
+                android:padding="13.3dp" />
+
+            <TextView
+                android:id="@+id/tv_more_series"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="13.3dp"
+                android:layout_marginBottom="13.3dp"
+                android:background="@color/color_cc333333"
+                android:fontFamily="@font/gmarket_sans_medium"
+                android:gravity="center"
+                android:paddingVertical="10dp"
+                android:text="더보기 >"
+                android:textColor="@color/color_777777"
+                android:textSize="13.3sp" />
+        </LinearLayout>
+    </androidx.core.widget.NestedScrollView>
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/rv_creator"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipToPadding="false"
+        android:padding="13.3dp"
+        android:visibility="gone" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/rv_content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipToPadding="false"
+        android:padding="13.3dp"
+        android:visibility="gone" />
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/rv_series"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipToPadding="false"
+        android:padding="13.3dp"
+        android:visibility="gone" />
+
+    <TextView
+        android:id="@+id/tv_result_x"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginVertical="40dp"
+        android:fontFamily="@font/gmarket_sans_medium"
+        android:gravity="center"
+        android:text="검색 결과가 없습니다."
+        android:textColor="@color/white"
+        android:textSize="18.3sp"
+        android:visibility="gone" />
+</LinearLayout>
diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml
new file mode 100644
index 0000000..85e3e13
--- /dev/null
+++ b/app/src/main/res/layout/item_search.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/black"
+    android:gravity="center_vertical"
+    android:orientation="horizontal">
+
+    <ImageView
+        android:id="@+id/iv_profile"
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:contentDescription="@null"
+        android:visibility="gone" />
+
+    <ImageView
+        android:id="@+id/iv_content"
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:contentDescription="@null"
+        android:visibility="gone" />
+
+    <ImageView
+        android:id="@+id/iv_series"
+        android:layout_width="60dp"
+        android:layout_height="85dp"
+        android:contentDescription="@null"
+        android:visibility="gone" />
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="13.3dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="@font/gmarket_sans_medium"
+            android:textColor="@color/color_eeeeee"
+            android:textSize="13.3sp"
+            tools:text="slefjeiwok" />
+
+        <TextView
+            android:id="@+id/tv_nickname"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="6.7dp"
+            android:fontFamily="@font/gmarket_sans_medium"
+            android:textColor="@color/color_777777"
+            android:textSize="10sp"
+            tools:ignore="SmallSp"
+            tools:text="slefjeiwok" />
+    </LinearLayout>
+</LinearLayout>