diff --git a/docs/usage.rst b/docs/usage.rst
index 2e1430c..9416401 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -506,6 +506,17 @@ Check `MetaCPAN `_ for updates.
cpan
The name used on CPAN, e.g. ``YAML``.
+Check CRAN
+~~~~~~~~~~
+::
+
+ source = "cran"
+
+Check `CRAN `_ for updates.
+
+cran
+ The name used on CRAN, e.g. ``ggplot2``.
+
Check Packagist
~~~~~~~~~~~~~~~
::
diff --git a/nvchecker_source/cran.py b/nvchecker_source/cran.py
new file mode 100644
index 0000000..43470cb
--- /dev/null
+++ b/nvchecker_source/cran.py
@@ -0,0 +1,25 @@
+# MIT licensed
+# Copyright (c) 2021- hubutui
+import configparser
+
+from nvchecker.api import session
+
+CRAN_URL = 'https://cran.r-project.org/src/contrib/PACKAGES'
+
+async def get_versions(url: str):
+ result = {}
+ res = await session.get(url)
+ config = configparser.ConfigParser()
+ for item in res.body.decode("UTF-8").split("\n\n"):
+ if item.startswith("Package: "):
+ rpkgname = item.split('\n')[0].replace(' ', '').split(':')[1]
+ config.read_string(f"[{rpkgname}]\n" + item)
+ result[rpkgname] = config[rpkgname]["version"]
+
+ return result
+
+async def get_version(name, conf, *, cache, **kwargs):
+ rpkgname = conf.get('cran', name)
+ versions = await cache.get(CRAN_URL, get_versions)
+
+ return versions[rpkgname]
diff --git a/tests/test_cran.py b/tests/test_cran.py
new file mode 100644
index 0000000..7789d21
--- /dev/null
+++ b/tests/test_cran.py
@@ -0,0 +1,11 @@
+# MIT licensed
+# Copyright (c) 2021- hubutui
+
+import pytest
+
+pytestmark = [pytest.mark.asyncio, pytest.mark.needs_net]
+
+async def test_cran(get_version):
+ assert await get_version("ggplot2", {
+ "source": "cran",
+ }) == "3.3.3"